79a616ad5d78c1166e5fe4dc2720b04e4ba86999
[platform/core/system/resourced.git] / src / common / config-parser.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
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 <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <assert.h>
23 #include <limits.h>
24
25 #include "util.h"
26 #include "trace.h"
27 #include "config-parser.h"
28 #include "proc-common.h"
29 #include "cpu-cgroup.h"
30 #include "swap-common.h"
31 #include "dedup-common.h"
32 #include "compact-common.h"
33
34 #define MAX_SECTION             64
35 #define CPU_INIT_PRIO   100
36
37 static int optimizer_config(struct parse_result *result, void *user_data)
38 {
39         if (!result)
40                 return RESOURCED_ERROR_INVALID_PARAMETER;
41
42         struct swap_conf *swap_conf = get_swap_conf();  
43         if (swap_conf == NULL) {
44                 _E("[DEBUG] swap configuration is NULL");
45                 return RESOURCED_ERROR_FAIL;
46         }
47
48         struct dedup_conf *dedup_conf = get_dedup_conf();       
49         if (dedup_conf == NULL) {
50                 _E("[DEBUG] dedup configuration is NULL");
51                 return RESOURCED_ERROR_FAIL;
52         }
53
54         struct compact_conf *compact_conf = get_compact_conf(); 
55         if (compact_conf == NULL) {
56                 _E("[DEBUG] compact configuration is NULL");
57                 return RESOURCED_ERROR_FAIL;
58         }
59
60         if (!strncmp(result->section, SWAP_SECTION, strlen(SWAP_SECTION)+1)) {
61                 if (!strncmp(result->name, ENABLE_CONF, strlen(ENABLE_CONF)+1)) {
62                         if (!strncmp(result->value, "yes", 4) ||
63                                 !strncmp(result->value, "1", 2) ||
64                                 !strncmp(result->value, "ok", 3))
65                                 swap_conf->enable = true;
66                         else if (!strncmp(result->value, "no", 3) ||
67                                 !strncmp(result->value, "0", 2))
68                                 swap_conf->enable = false;
69                         else {
70                                 _E("[DEBUG] Unknown value for %s", result->name);
71                                 return RESOURCED_ERROR_FAIL;
72                         }
73                 }
74                 else if (!strncmp(result->name, RECLAIM_AT_BOOT_CONF,
75                                         strlen(RECLAIM_AT_BOOT_CONF)+1)) {
76                         if (!strncmp(result->value, "yes", 4) ||
77                                 !strncmp(result->value, "1", 2) ||
78                                 !strncmp(result->value, "ok", 3))
79                                 swap_conf->boot_reclaim_enable = true;
80                         else if (!strncmp(result->value, "no", 3) ||
81                                 !strncmp(result->value, "0", 2))
82                                 swap_conf->boot_reclaim_enable = false;
83                         else {
84                                 _E("[DEBUG] Unknown value for %s", result->name);
85                                 return RESOURCED_ERROR_FAIL;
86                         }
87                 }
88                 else if (!strncmp(result->name, TYPE_CONF,
89                                         strlen(TYPE_CONF)+1)) {
90                         if (strlen(result->value) + 1 > sizeof(swap_conf->type)) {
91                                 _E("Size of swap_conf->type is not enough");
92                                 return RESOURCED_ERROR_OUT_OF_MEMORY;
93                         }
94                         strncpy(swap_conf->type, result->value, sizeof(swap_conf->type) - 1);
95                 }
96                 else if (!strncmp(result->name, VIP_GROUP_SWAPPINESS_CONF,
97                                         strlen(VIP_GROUP_SWAPPINESS_CONF)+1)) {
98                         swap_conf->swappiness[CGROUP_VIP] = atoi(result->value);
99                 }
100                 else if (!strncmp(result->name, HIGH_GROUP_SWAPPINESS_CONF,
101                                         strlen(HIGH_GROUP_SWAPPINESS_CONF)+1)) {
102                         swap_conf->swappiness[CGROUP_HIGH] = atoi(result->value);
103                 }
104                 else if (!strncmp(result->name, MEDIUM_GROUP_SWAPPINESS_CONF,
105                                         strlen(MEDIUM_GROUP_SWAPPINESS_CONF)+1)) {
106                         swap_conf->swappiness[CGROUP_MEDIUM] = atoi(result->value);
107                 }
108                 else if (!strncmp(result->name, LOWEST_GROUP_SWAPPINESS_CONF,
109                                         strlen(LOWEST_GROUP_SWAPPINESS_CONF)+1)) {
110                         swap_conf->swappiness[CGROUP_LOW] = atoi(result->value);
111                 }
112                 else {
113                         _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
114                                         result->name, result->value, result->section);
115                 }
116         }
117         else if (!strncmp(result->section, ZRAM_SECTION, strlen(ZRAM_SECTION)+1)) {
118                 if (!strncmp(result->name, COMP_ALGORITHM_CONF, strlen(COMP_ALGORITHM_CONF)+1)) {
119                         if (strlen(result->value) + 1 > sizeof(swap_conf->zram.algorithm)) {
120                                 _E("Size of swap_conf->zram.algorithm is not enough");
121                                 return RESOURCED_ERROR_OUT_OF_MEMORY;
122                         }
123                         strncpy(swap_conf->zram.algorithm, result->value,
124                                         sizeof(swap_conf->zram.algorithm) - 1); 
125                 }
126                 else if (!strncmp(result->name, RATIO_CONF, strlen(RATIO_CONF)+1)) {
127                         swap_conf->zram.ratio = atof(result->value);    
128                 }
129                 else {
130                         _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
131                                         result->name, result->value, result->section);
132                 }
133         }
134         else if (!strncmp(result->section, ZSWAP_SECTION, strlen(ZSWAP_SECTION)+1)) {
135                 if (!strncmp(result->name, CRYPT_TYPE_CONF, strlen(CRYPT_TYPE_CONF)+1)) {
136                         if (strlen(result->value) + 1 > sizeof(swap_conf->zswap.type)) {
137                                 _E("Size of swap_conf->zswap.type is not enough");
138                                 return RESOURCED_ERROR_OUT_OF_MEMORY;
139                         }
140                         strncpy(swap_conf->zswap.type, result->value,
141                                         sizeof(swap_conf->zswap.type) - 1);
142                 }
143                 else if (!strncmp(result->name, FILE_SIZE_CONF, strlen(FILE_SIZE_CONF)+1)) {
144                         swap_conf->zswap.filesize = atol(result->value); 
145                 }
146                 else if (!strncmp(result->name, POOL_RATIO_CONF, strlen(POOL_RATIO_CONF)+1)) {
147                         swap_conf->zswap.pool_ratio = atof(result->value);
148                 }
149                 else if (!strncmp(result->name, POOL_TYPE_CONF, strlen(POOL_TYPE_CONF)+1)) {
150                         if (strlen(result->value) + 1 > sizeof(swap_conf->zswap.pool_type)) {
151                                 _E("Size of swap_conf->zswap.pool_type is not enough");
152                                 return RESOURCED_ERROR_OUT_OF_MEMORY;
153                         }
154                         strncpy(swap_conf->zswap.pool_type, result->value,
155                                         sizeof(swap_conf->zswap.pool_type) - 1);
156                 }
157                 else {
158                         _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
159                                         result->name, result->value, result->section);
160                 }
161         }
162         else if (!strncmp(result->section, FILE_SWAP_SECTION, strlen(FILE_SWAP_SECTION)+1)) {
163                 if (!strncmp(result->name, CRYPT_TYPE_CONF, strlen(CRYPT_TYPE_CONF)+1)) {
164                         if (strlen(result->value) + 1 > sizeof(swap_conf->fileswap.type)) {
165                                 _E("Size of swap_conf->fileswap.type is not enough");
166                                 return RESOURCED_ERROR_OUT_OF_MEMORY;
167                         }
168                         strncpy(swap_conf->fileswap.type, result->value,
169                                         sizeof(swap_conf->fileswap.type) - 1);
170                 }
171                 else if (!strncmp(result->name, FILE_SIZE_CONF, strlen(FILE_SIZE_CONF)+1)) {
172                         swap_conf->fileswap.filesize = atol(result->value); 
173                 }
174                 else {
175                         _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
176                                         result->name, result->value, result->section);
177                 }
178         }
179         else if (!strncmp(result->section, DEDUP_SECTION, strlen(DEDUP_SECTION)+1)) {
180                 if (!strncmp(result->name, ENABLE_CONF, strlen(ENABLE_CONF)+1)) {
181                         if (!strncmp(result->value, "yes", 4) ||
182                                 !strncmp(result->value, "1", 2) ||
183                                 !strncmp(result->value, "ok", 3))
184                                 dedup_conf->enable = true;
185                         else if (!strncmp(result->value, "no", 3) ||
186                                 !strncmp(result->value, "0", 2))
187                                 dedup_conf->enable = false;
188                         else {
189                                 _E("[DEBUG] Unknown value for %s", result->name);
190                                 return RESOURCED_ERROR_FAIL;
191                         }
192                 }
193                 else if (!strncmp(result->name, DEDUP_AT_BOOT_CONF, strlen(DEDUP_AT_BOOT_CONF)+1)) {
194                         if (!strncmp(result->value, "yes", 4) ||
195                                 !strncmp(result->value, "1", 2) ||
196                                 !strncmp(result->value, "ok", 3))
197                                 dedup_conf->boot_dedup_enable = true;
198                         else if (!strncmp(result->value, "no", 3) ||
199                                 !strncmp(result->value, "0", 2))
200                                 dedup_conf->boot_dedup_enable = false;
201                         else {
202                                 _E("[DEBUG] Unknown value for %s", result->name);
203                                 return RESOURCED_ERROR_FAIL;
204                         }
205                 }
206                 else if (!strncmp(result->name, SCAN_ON_LOWMEM_CONF, strlen(SCAN_ON_LOWMEM_CONF)+1)) {
207                         if (!strncmp(result->value, "yes", 4) ||
208                                 !strncmp(result->value, "1", 2) ||
209                                 !strncmp(result->value, "ok", 3) ||
210                                 !strncmp(result->value, "true", 5))
211                                 dedup_conf->scan_on_lowmem = true;
212                         else if (!strncmp(result->value, "no", 3) ||
213                                 !strncmp(result->value, "0", 2) ||
214                                 !strncmp(result->value, "false", 6))
215                                 dedup_conf->scan_on_lowmem = false;
216                         else {
217                                 _E("[DEBUG] Unknown value for %s", result->name);
218                                 return RESOURCED_ERROR_FAIL;
219                         }
220                 }
221                 else {
222                         _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
223                                         result->name, result->value, result->section);
224                 }
225         }
226         else if (!strncmp(result->section, KSM_SECTION, strlen(KSM_SECTION)+1)) {
227                 if (!strncmp(result->name, MODE_CONF, strlen(MODE_CONF)+1)) {
228                         if (strlen(result->value) + 1 > sizeof(dedup_conf->ksm.mode)) {
229                                 _E("Size of swap_conf->type is not enough");
230                                 return RESOURCED_ERROR_OUT_OF_MEMORY;
231                         }
232                         strncpy(dedup_conf->ksm.mode, result->value,
233                                         sizeof(dedup_conf->ksm.mode) - 1);
234                 }
235                 else if (!strncmp(result->name, PAGES_TO_SCAN_CONF, strlen(PAGES_TO_SCAN_CONF)+1)) {
236                         dedup_conf->ksm.pages = atoi(result->value);
237                 }
238                 else if (!strncmp(result->name, PAGES_TO_SCAN_WITH_BOOST_CONF,
239                                         strlen(PAGES_TO_SCAN_WITH_BOOST_CONF)+1)) {
240                         dedup_conf->ksm.boost_pages = atoi(result->value);
241                 }
242                 else {
243                         _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
244                                         result->name, result->value, result->section);
245                 }
246         }
247         else if (!strncmp(result->section, COMPACTION_SECTION, strlen(COMPACTION_SECTION)+1)) {
248                 if (!strncmp(result->name, ENABLE_CONF, strlen(ENABLE_CONF)+1)) {
249                         if (!strncmp(result->value, "yes", 4) ||
250                                 !strncmp(result->value, "1", 2) ||
251                                 !strncmp(result->value, "ok", 3) ||
252                                 !strncmp(result->value, "true", 5))
253                                 compact_conf->enable = true;
254                         else if (!strncmp(result->value, "no", 3) ||
255                                 !strncmp(result->value, "0", 2) ||
256                                 !strncmp(result->value, "false", 6))
257                                 compact_conf->enable = false;
258                         else {
259                                 _E("[DEBUG] Unknown value for %s", result->name);
260                                 return RESOURCED_ERROR_FAIL;
261                         }
262                 }
263                 else if (!strncmp(result->name, FRAG_LEVEL_CONF, strlen(FRAG_LEVEL_CONF)+1)) {
264                         compact_conf->frag_level = atoi(result->value);
265                 }
266                 else {
267                         _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
268                                         result->name, result->value, result->section);
269                 }
270         }
271         else {
272                 _E("[DEBUG] Unknown section name (%s) and value (%s) on section (%s)",
273                                 result->name, result->value, result->section);
274         }
275         
276         return RESOURCED_ERROR_NONE;
277 }
278
279
280 static int limiter_config(struct parse_result *result, void *user_data)
281 {
282         if (!result)
283                 return RESOURCED_ERROR_INVALID_PARAMETER;
284
285         struct memcg_conf *memcg_conf = get_memcg_conf();       
286         if (memcg_conf == NULL) {
287                 _E("[DEBUG] memory cgroup configuration is NULL");
288                 return RESOURCED_ERROR_FAIL;
289         }
290
291         if (!strncmp(result->section, MEMORY_GROUP_LIMIT_SECTION,
292                                 strlen(MEMORY_GROUP_LIMIT_SECTION)+1)) {
293                 char *ptr = strchr(result->value, '%');
294                 if (ptr == NULL) {
295                         _E("[DEBUG] Cannot find '%%' in the string (%s)", result->value);
296                         return RESOURCED_ERROR_FAIL;
297                 }
298                 else
299                         *ptr = '\0';
300
301                 if (!strncmp(result->name, VIP_GROUP_LIMIT_CONF,
302                                         strlen(VIP_GROUP_LIMIT_CONF) + 1)) {
303                         memcg_conf->cgroup_limit[CGROUP_VIP] = atof(result->value);
304                 }
305                 else if (!strncmp(result->name, HIGH_GROUP_LIMIT_CONF,
306                                         strlen(HIGH_GROUP_LIMIT_CONF) + 1)) {
307                         memcg_conf->cgroup_limit[CGROUP_HIGH] = atof(result->value);
308                 }
309                 else if (!strncmp(result->name, MEDIUM_GROUP_LIMIT_CONF,
310                                         strlen(MEDIUM_GROUP_LIMIT_CONF) + 1)) {
311                         memcg_conf->cgroup_limit[CGROUP_MEDIUM] = atof(result->value);
312                 }
313                 else if (!strncmp(result->name, LOWEST_GROUP_LIMIT_CONF,
314                                         strlen(LOWEST_GROUP_LIMIT_CONF) + 1)) {
315                         memcg_conf->cgroup_limit[CGROUP_LOW] = atof(result->value);
316                 }
317                 else {
318                         _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
319                                         result->name, result->value, result->section);
320                 }
321         }
322         else if (!strncmp(result->section, MEMORY_LEVEL_THRESHOLD_SECTION,
323                                 strlen(MEMORY_LEVEL_THRESHOLD_SECTION)+1)) {
324
325                 if (!strncmp(result->name, OOM_POPUP_CONF,
326                                         strlen(OOM_POPUP_CONF) + 1)) {
327                         if (!strncmp(result->value, "yes", 4) ||
328                                 !strncmp(result->value, "1", 2) ||
329                                 !strncmp(result->value, "ok", 3))
330                                 memcg_conf->oom_popup = true;
331                         else if (!strncmp(result->value, "no", 3) ||
332                                 !strncmp(result->value, "0", 2))
333                                 memcg_conf->oom_popup = false;
334                         else {
335                                 _E("[DEBUG] Unknown value for %s", result->name);
336                                 return RESOURCED_ERROR_FAIL;
337                         }
338                 }
339                 else {
340                         char temp = '\0';
341                         int error = RESOURCED_ERROR_NONE;
342                         bool percent;
343                         char *ptr = strchr(result->value, '%');
344                         if (ptr == NULL) {
345                                 ptr = strchr(result->value, 'B');
346                                 if (ptr == NULL) {
347                                         _E("[DEBUG] Cannot find 'B' in the string (%s)", result->value);
348                                         return RESOURCED_ERROR_FAIL;
349                                 }
350
351                                 if (result->value > (ptr - 1)) {
352                                         _E("[DEBUG] Size of string should be larger than 1");
353                                         return RESOURCED_ERROR_FAIL;
354                                 }
355
356                                 temp = *(ptr - 1);
357                                 *(ptr - 1) = '\0';
358                                 percent = false;
359                         }
360                         else { 
361                                 *ptr = '\0';
362                                 percent = true;
363                         }
364
365                         if (!strncmp(result->name, MEDIUM_LEVEL_CONF,
366                                                 strlen(MEDIUM_LEVEL_CONF) + 1)) {
367                                 error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_MEDIUM, result->value);
368                         }
369                         else if (!strncmp(result->name, LOW_LEVEL_CONF,
370                                                 strlen(LOW_LEVEL_CONF) + 1)) {
371                                 error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_LOW, result->value);
372                         }
373                         else if (!strncmp(result->name, CRITICAL_LEVEL_CONF,
374                                                 strlen(CRITICAL_LEVEL_CONF) + 1)) {
375                                 error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_CRITICAL, result->value);
376                         }
377                         else if (!strncmp(result->name, OOM_LEVEL_CONF,
378                                                 strlen(OOM_LEVEL_CONF) + 1)) {
379                                 error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_OOM, result->value);
380                         }
381
382                         else {
383                                 _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
384                                                 result->name, result->value, result->section);
385                         }
386                         
387                         return error;
388                 }
389         }
390         else if (!strncmp(result->section, MEMORY_APP_TYPE_LIMIT_SECTION,
391                                 strlen(MEMORY_APP_TYPE_LIMIT_SECTION)+1)) {
392                 int error = RESOURCED_ERROR_NONE;
393
394                 if (!strncmp(result->name, SERVICE_PER_APP_LIMIT_ACTION,
395                                         strlen(SERVICE_PER_APP_LIMIT_ACTION) + 1)) {
396                         error = set_mem_action_conf(&memcg_conf->service, result->value);
397                 }
398                 else if (!strncmp(result->name, WIDGET_PER_APP_LIMIT_ACTION,
399                                         strlen(WIDGET_PER_APP_LIMIT_ACTION) + 1)) {
400                         error = set_mem_action_conf(&memcg_conf->widget, result->value);
401                 }
402                 else if (!strncmp(result->name, GUI_PER_APP_LIMIT_ACTION,
403                                         strlen(GUI_PER_APP_LIMIT_ACTION) + 1)) {
404                         error = set_mem_action_conf(&memcg_conf->guiapp, result->value);
405                 }
406                 else {
407                         _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
408                                         result->name, result->value, result->section);
409                 }
410
411                 return error;
412         }
413         else if (!strncmp(result->section, MEMORY_APP_STATUS_LIMIT_SECTION,
414                                 strlen(MEMORY_APP_STATUS_LIMIT_SECTION)+1)) {
415                 int error = RESOURCED_ERROR_NONE;
416
417                 if (!strncmp(result->name, BACKGROUND_PER_APP_LIMIT_ACTION,
418                                         strlen(BACKGROUND_PER_APP_LIMIT_ACTION) + 1)) {
419                         error = set_mem_action_conf(&memcg_conf->background, result->value);
420                 }
421                 else {
422                         _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
423                                         result->name, result->value, result->section);
424                 }
425
426                 return error;
427         }
428         else if (!strncmp(result->section, CPU_AFFINITY_SECTION,
429                                 strlen(CPU_AFFINITY_SECTION)+1)) {
430                 int error = RESOURCED_ERROR_NONE;
431
432                 if (!strncmp(result->name, FOREGROUND_APPS,
433                                         strlen(FOREGROUND_APPS) + 1)) {
434                         error = set_cpucg_conf(result->name, result->value);
435                 }
436                 else {
437                         _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
438                                         result->name, result->value, result->section);
439                 }
440
441                 return error;
442         }
443         else {
444                 _E("[DEBUG] Unknown section name (%s) and value (%s) on section (%s)",
445                                 result->name, result->value, result->section);
446         }
447         
448         return RESOURCED_ERROR_NONE;
449 }
450
451 static int vendor_config(struct parse_result *result, void *user_data)
452 {
453         int *config_type = (int *)user_data;
454         static struct proc_conf_info *pci = NULL;
455
456         if (!result || !user_data)
457                 return RESOURCED_ERROR_INVALID_PARAMETER;
458
459         if (strncmp(result->section, PER_PROCESS_SECTION, strlen(PER_PROCESS_SECTION)+1))
460                 return RESOURCED_ERROR_NONE;
461
462         if (!strncmp(result->name, SERVICE_NAME_CONF, strlen(SERVICE_NAME_CONF)+1) ||
463                 !strncmp(result->name, APP_NAME_CONF, strlen(APP_NAME_CONF)+1)) {
464                 pci = fixed_app_and_service_exist_check(result->value,
465                                 result->name[0] == 'A' ? APP_TYPE : SERVICE_TYPE);
466                 if (pci == NULL) {
467                         pci = (struct proc_conf_info *)calloc(1, sizeof(struct proc_conf_info));
468                         if (pci == NULL) {
469                                 _E("Failed to allocate memory during parsing vendor configurations");
470                                 return RESOURCED_ERROR_OUT_OF_MEMORY;
471                         }
472                         pci->mem_type = CGROUP_TOP;
473                         pci->cpu_type = CGROUP_TOP;
474                         pci->cpu_priority = CPU_INIT_PRIO;
475                         pci->watchdog_action = PROC_ACTION_KILL;
476                         pci->fail_action = PROC_ACTION_IGNORE;
477                         strncpy(pci->name, result->value, sizeof(pci->name)-1);
478
479                         if (result->name[0] == 'A') {
480                                 fixed_app_list_insert(pci);
481                         }
482                         else {
483                                 fixed_service_list_insert(pci);
484                         }
485                 }
486         }
487         else if (!strncmp(result->name, CPU_CGROUP_NAME_CONF, strlen(CPU_CGROUP_NAME_CONF)+1) &&
488                         *config_type == LIMITER_CONFIG) {
489                 if (!pci) {
490                         _E("process configuration information pointer should not be NULL");
491                         return RESOURCED_ERROR_FAIL;
492                 }
493
494                 if (!strncmp(result->value, CGROUP_VIP_VALUE_CONF,
495                         strlen(CGROUP_VIP_VALUE_CONF) +1)) {
496                         pci->cpu_type = CGROUP_VIP;
497                 }
498                 else if (!strncmp(result->value, CGROUP_HIGH_VALUE_CONF,
499                         strlen(CGROUP_HIGH_VALUE_CONF) +1)) {
500                         pci->cpu_type = CGROUP_HIGH;
501                 }
502                 else if (!strncmp(result->value, CGROUP_MEDIUM_VALUE_CONF,
503                         strlen(CGROUP_MEDIUM_VALUE_CONF) +1)) {
504                         pci->cpu_type = CGROUP_MEDIUM;
505                 }
506                 else if (!strncmp(result->value, CGROUP_LOW_VALUE_CONF,
507                         strlen(CGROUP_LOW_VALUE_CONF) +1)) {
508                         pci->cpu_type = CGROUP_LOW;
509                 }
510                 else {
511                         _E("invalid parameter (%s)", result->value);
512                         return RESOURCED_ERROR_INVALID_PARAMETER;
513                 }
514         }
515         else if (!strncmp(result->name, MEM_CGROUP_NAME_CONF, strlen(MEM_CGROUP_NAME_CONF)+1) &&
516                         *config_type == LIMITER_CONFIG) {
517                 if (!pci) {
518                         _E("process configuration information pointer should not be NULL");
519                         return RESOURCED_ERROR_FAIL;
520                 }
521
522                 if (!strncmp(result->value, CGROUP_VIP_VALUE_CONF,
523                         strlen(CGROUP_VIP_VALUE_CONF) +1)) {
524                         pci->mem_type = CGROUP_VIP;
525                 }
526                 else if (!strncmp(result->value, CGROUP_HIGH_VALUE_CONF,
527                         strlen(CGROUP_HIGH_VALUE_CONF) +1)) {
528                         pci->mem_type = CGROUP_HIGH;
529                 }
530                 else if (!strncmp(result->value, CGROUP_MEDIUM_VALUE_CONF,
531                         strlen(CGROUP_MEDIUM_VALUE_CONF) +1)) {
532                         pci->mem_type = CGROUP_MEDIUM;
533                 }
534                 else if (!strncmp(result->value, CGROUP_LOW_VALUE_CONF,
535                         strlen(CGROUP_LOW_VALUE_CONF) +1)) {
536                         pci->mem_type = CGROUP_LOW;
537                 }
538                 else {
539                         _E("invalid parameter (%s)", result->value);
540                         return RESOURCED_ERROR_INVALID_PARAMETER;
541                 }
542         }
543         else if (!strncmp(result->name, MEM_LIMIT_ACTION_NAME_CONF,
544                 strlen(MEM_LIMIT_ACTION_NAME_CONF)+1) && *config_type == LIMITER_CONFIG) {
545                 int error;
546
547                 if (!pci) {
548                         _E("process configuration information pointer should not be NULL");
549                         return RESOURCED_ERROR_FAIL;
550                 }
551                 
552                 error = set_mem_action_conf(&pci->mem_action, result->value);
553                 return error;   
554         }
555         else if (!strncmp(result->name, CPU_PRIORITY_NAME_CONF, strlen(CPU_PRIORITY_NAME_CONF)+1) &&
556                         *config_type == LIMITER_CONFIG) {
557                 if (!pci) {
558                         _E("process configuration information pointer should not be NULL");
559                         return RESOURCED_ERROR_FAIL;
560                 }
561                 pci->cpu_priority = atoi(result->value);
562         }
563         else if (!strncmp(result->name, ACTION_ON_FAILURE_NAME_CONF,
564                                 strlen(ACTION_ON_FAILURE_NAME_CONF)+1) && *config_type == PROCESS_CONFIG) {
565                 if (!pci) {
566                         _E("process configuration information pointer should not be NULL");
567                         return RESOURCED_ERROR_FAIL;
568                 }
569
570                 if (!strncmp(result->value, ACTION_REBOOT_VALUE_CONF,
571                                         strlen(ACTION_REBOOT_VALUE_CONF) +1)) {
572                         pci->fail_action = PROC_ACTION_REBOOT;
573                 }
574                 else {
575                         _E("invalid parameter (%s)", result->value);
576                         return RESOURCED_ERROR_INVALID_PARAMETER;
577                 }
578         }
579         else if (!strncmp(result->name, WATCHDOG_ACTION_NAME_CONF,
580                                 strlen(WATCHDOG_ACTION_NAME_CONF)+1) && *config_type == PROCESS_CONFIG) {
581                 if (!pci) {
582                         _E("process configuration information pointer should not be NULL");
583                         return RESOURCED_ERROR_FAIL;
584                 }
585
586                 if (!strncmp(result->value, ACTION_IGNORE_VALUE_CONF,
587                                         strlen(ACTION_IGNORE_VALUE_CONF) +1)) {
588                         pci->watchdog_action = PROC_ACTION_IGNORE;
589                 }
590                 else if (!strncmp(result->value, ACTION_KILL_VALUE_CONF,
591                                         strlen(ACTION_KILL_VALUE_CONF) +1)) {
592                         pci->watchdog_action = PROC_ACTION_KILL;
593                 }
594                 else {
595                         _E("invalid parameter (%s)", result->value);
596                         return RESOURCED_ERROR_INVALID_PARAMETER;
597                 }
598         }
599         else {
600                 _E("Unknown configuration name (%s) and value (%s) on section (%s)",
601                                 result->name, result->value, result->section);
602         }
603
604         return RESOURCED_ERROR_NONE;
605 }
606
607 static void load_per_vendor_configs(const char *dir, int func(struct parse_result *result,
608                                                                 void *user_data), void *user_data)
609 {
610         int count;
611         int idx;
612         struct dirent **namelist;
613
614         if ((count = scandir(dir, &namelist, NULL, alphasort)) == -1) {
615                 _W("failed to opendir (%s)", dir);
616                 return;
617         }
618
619         for (idx = 0; idx < count; idx++) {
620                 char path[PATH_MAX] = {0, };
621
622                 if (!strstr(namelist[idx]->d_name, CONF_FILE_SUFFIX))
623                         continue;
624
625                 snprintf(path, sizeof(path), "%s/%s", dir, namelist[idx]->d_name);
626                 config_parse(path, func, user_data);
627                 free(namelist[idx]);
628         }
629
630         free(namelist);
631 }
632
633 void resourced_parse_vendor_configs(void)
634 {
635         int config_type;
636
637         fixed_app_and_service_list_init();
638
639         /* Load configurations in limiter.conf and limiter.conf.d/ */
640         config_parse(LIMITER_CONF_FILE, limiter_config, NULL);
641         config_type = LIMITER_CONFIG;
642         load_per_vendor_configs(LIMITER_CONF_DIR, vendor_config, &config_type);
643
644         /* Load configurations in optimizer.conf */
645         config_parse(OPTIMIZER_CONF_FILE, optimizer_config, NULL);
646
647         config_type = PROCESS_CONFIG;
648         load_per_vendor_configs(PROC_CONF_DIR, vendor_config, &config_type);
649 }
650
651 void resourced_free_vendor_configs(void)
652 {
653         fixed_app_and_service_list_exit();
654 }
655
656 int config_parse(const char *file_name, int cb(struct parse_result *result,
657                         void *user_data), void *user_data)
658 {
659         FILE *f = NULL;
660         struct parse_result result;
661         /* use stack for parsing */
662         char line[LINE_MAX];
663         char section[MAX_SECTION];
664         char *start, *end, *name, *value;
665         int lineno = 0, ret = 0;
666
667         if (!file_name || !cb) {
668                 ret = -EINVAL;
669                 goto error;
670         }
671
672         /* open conf file */
673         f = fopen(file_name, "r");
674         if (!f) {
675                 _E("Failed to open file %s", file_name);
676                 ret = -EIO;
677                 goto error;
678         }
679
680         /* parsing line by line */
681         while (fgets(line, LINE_MAX, f) != NULL) {
682                 lineno++;
683
684                 start = line;
685                 truncate_nl(start);
686                 start = strstrip(start);
687
688                 if (*start == COMMENT) {
689                         continue;
690                 } else if (*start == '[') {
691                         /* parse section */
692                         end = strchr(start, ']');
693                         if (!end || *end != ']') {
694                                 ret = -EBADMSG;
695                                 goto error;
696                         }
697
698                         *end = '\0';
699                         strncpy(section, start + 1, sizeof(section)-1);
700                         section[MAX_SECTION-1] = '\0';
701                 } else if (*start) {
702                         /* parse name & value */
703                         end = strchr(start, '=');
704                         if (!end || *end != '=') {
705                                 ret = -EBADMSG;
706                                 goto error;
707                         }
708                         *end = '\0';
709                         name = strstrip(start);
710                         value = strstrip(end + 1);
711                         end = strchr(value, COMMENT);
712                         if (end && *end == COMMENT) {
713                                 *end = '\0';
714                                 value = strstrip(value);
715                         }
716
717                         result.section = section;
718                         result.name = name;
719                         result.value = value;
720                         /* callback with parse result */
721                         ret = cb(&result, user_data);
722                         if (ret < 0) {
723                                 ret = -EBADMSG;
724                                 goto error;
725                         }
726                 }
727         }
728         return 0;
729
730 error:
731         if (f)
732                 fclose(f);
733         _E("Failed to read %s:%d!", file_name, lineno);
734         return ret;
735 }
736
737 static int config_table_lookup(void *table,
738                                const char *section,
739                                const char *lvalue,
740                                ConfigParserCallback *func,
741                                int *ltype,
742                                void **data)
743 {
744         ConfigTableItem *t;
745
746         assert(table);
747         assert(lvalue);
748         assert(func);
749         assert(ltype);
750         assert(data);
751
752         for (t = table; t->lvalue; t++) {
753
754                 if (!streq(lvalue, t->lvalue))
755                         continue;
756
757                 if (!streq_ptr(section, t->section))
758                         continue;
759
760                 *func = t->cb;
761                 *ltype = t->ltype;
762                 *data = t->data;
763                 return 1;
764         }
765
766         return 0;
767 }
768
769 /* Run the user supplied parser for an assignment */
770 static int config_parse_table(const char *filename,
771                               unsigned line,
772                               void *table,
773                               const char *section,
774                               const char *lvalue,
775                               const char *rvalue)
776 {
777         ConfigParserCallback cb = NULL;
778         int ltype = 0;
779         void *data = NULL;
780         int r;
781
782         assert(filename);
783         assert(section);
784         assert(lvalue);
785         assert(rvalue);
786
787         r = config_table_lookup(table,
788                                 section,
789                                 lvalue,
790                                 &cb,
791                                 &ltype,
792                                 &data);
793         if (r <= 0)
794                 return r;
795
796         if (cb)
797                 return cb(filename,
798                           line,
799                           section,
800                           lvalue,
801                           ltype,
802                           rvalue,
803                           data);
804
805         return 0;
806 }
807
808 int config_parse_new(const char *filename, void *table)
809 {
810         _cleanup_fclose_ FILE *f = NULL;
811         char *sections[MAX_SECTION] = { 0 };
812         char *section = NULL, *n, *e, l[LINE_MAX];
813         size_t len;
814         int i, r, num_section = 0;
815         bool already;
816         unsigned line = 0;
817
818         assert(filename);
819
820         f = fopen(filename, "r");
821         if (!f) {
822                 const int saved_errno = errno;
823                 _E("Failed to open file %s", filename); // can modify errno
824                 return -saved_errno;
825         }
826
827         while (!feof(f)) {
828                 _cleanup_free_ char *lvalue = NULL, *rvalue = NULL;
829                 char *rs = NULL;
830
831                 if (fgets(l, LINE_MAX, f) == NULL) {
832                         if (feof(f))
833                                 break;
834
835                         _E("Failed to parse configuration file '%s': %m", filename);
836                         r = -errno;
837                         goto finish;
838                 }
839
840                 line++;
841                 truncate_nl(l);
842
843                 if (strchr(COMMENTS NEWLINE, *l))
844                         continue;
845
846                 if (*l == '[') {
847                         len = strlen(l);
848                         if (l[len-1] != ']') {
849                                 _E("Error: Invalid section header: %s", l);
850                                 r = -EBADMSG;
851                                 goto finish;
852                         }
853
854                         n = strndup(l+1, len-2);
855                         if (!n) {
856                                 r = -ENOMEM;
857                                 goto finish;
858                         }
859
860                         already = false;
861                         for (i = 0; i < num_section; i++) {
862                                 if (streq(n, sections[i])) {
863                                         section = sections[i];
864                                         already = true;
865                                         free(n);
866                                         break;
867                                 }
868                         }
869
870                         if (already)
871                                 continue;
872
873                         section = n;
874                         sections[num_section] = n;
875                         num_section++;
876                         if (num_section > MAX_SECTION) {
877                                 _E("Error: max number of section reached: %d", num_section);
878                                 r = -EOVERFLOW;
879                                 goto finish;
880                         }
881
882                         continue;
883                 }
884
885                 if (!section)
886                         continue;
887
888                 e = strchr(l, '=');
889                 if (e == NULL) {
890                         _D("Warning: config: no '=' character in line '%s'.", l);
891                         continue;
892                 }
893
894                 lvalue = strndup(l, e-l);
895                 if (!lvalue) {
896                         r = -ENOMEM;
897                         goto finish;
898                 }
899
900                 strstrip(lvalue);
901
902                 rs = strstrip(e+1);
903                 rvalue = strdup(rs);
904                 if (!rvalue) {
905                         r = -ENOMEM;
906                         goto finish;
907                 }
908
909                 strstrip(rvalue);
910
911                 r = config_parse_table(filename,
912                                        line,
913                                        table,
914                                        section,
915                                        lvalue,
916                                        rvalue);
917                 if (r < 0)
918                         goto finish;
919         }
920
921         r = 0;
922
923 finish:
924         for (i = 0; i < num_section; i++)
925                 if (sections[i])
926                         free(sections[i]);
927
928         return r;
929 }
930
931 int config_parse_dir(const char *dir, ConfigParseFunc fp, void *data)
932 {
933         _cleanup_closedir_ DIR *d = NULL;
934         struct dirent *de;
935
936         d = opendir(dir);
937         if (!d) {
938                 _E("Failed to open dir: %s", dir);
939                 return errno;
940         }
941
942         for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) {
943                 if (!de) {
944                         if (errno > 0)
945                                 return -errno;
946                         break;
947                 } else if (streq(de->d_name, ".") || streq(de->d_name, "..")) {
948                         continue;
949                 }
950
951                 _cleanup_free_ char *path = NULL;
952                 int r;
953
954                 if (de->d_type != DT_REG)
955                         continue;
956
957                 r = asprintf(&path, "%s/%s", dir, de->d_name);
958                 if (r < 0)
959                         return -ENOMEM;
960
961                 r = fp(path, data);
962                 /* Do not just break loop until parse all file of
963                  * dir. Just only put log */
964                 if (r < 0)
965                         _D("Failed to parse config: %s", de->d_name);
966         }
967
968         return 0;
969 }
970
971 int config_parse_bool(const char *filename,
972                       unsigned line,
973                       const char *section,
974                       const char *lvalue,
975                       int ltype,
976                       const char *rvalue,
977                       void *data)
978 {
979         int k;
980         bool *b = data;
981
982         assert(filename);
983         assert(lvalue);
984         assert(rvalue);
985         assert(data);
986
987         k = parse_boolean(rvalue);
988         if (k < 0) {
989                 _E("Failed to parse boolean value, ignoring: %s", rvalue);
990                 return 0;
991         }
992
993         *b = !!k;
994
995         return 0;
996 }
997
998 #define DEFINE_PARSER(type, vartype, conv_func)          \
999         int config_parse_##type(                                        \
1000                                 const char *filename,                   \
1001                                 unsigned line,                          \
1002                                 const char *section,                    \
1003                                 const char *lvalue,                     \
1004                                 int ltype,                              \
1005                                 const char *rvalue,                     \
1006                                 void *data) {                           \
1007                                                                                                                 \
1008                 vartype *i = data;                                      \
1009                                                                         \
1010                 assert(filename);                                       \
1011                 assert(lvalue);                                         \
1012                 assert(rvalue);                                         \
1013                 assert(data);                                           \
1014                                                                         \
1015                 *i = conv_func(rvalue);                          \
1016                 return 0;                                               \
1017                 }
1018
1019 DEFINE_PARSER(int, int, atoi)
1020 DEFINE_PARSER(float, float, atof)
1021 DEFINE_PARSER(long, long, atol)
1022
1023 int config_parse_string(const char *filename,
1024                         unsigned line,
1025                         const char *section,
1026                         const char *lvalue,
1027                         int ltype,
1028                         const char *rvalue,
1029                         void *data)
1030 {
1031         char **s = data, *n;
1032
1033         assert(filename);
1034         assert(lvalue);
1035         assert(rvalue);
1036         assert(data);
1037
1038         if (is_empty(rvalue))
1039                 n = NULL;
1040         else {
1041                 n = strdup(rvalue);
1042                 if (!n)
1043                         return -ENOMEM;
1044         }
1045
1046         free(*s);
1047         *s = n;
1048
1049         return 0;
1050 }
1051
1052 int config_parse_bytes(const char *filename,
1053                        unsigned line,
1054                        const char *section,
1055                        const char *lvalue,
1056                        int ltype,
1057                        const char *rvalue,
1058                        void *data)
1059 {
1060         size_t *s = data;
1061         int r;
1062
1063         assert(filename);
1064         assert(lvalue);
1065         assert(rvalue);
1066         assert(data);
1067
1068         if (is_empty(rvalue))
1069                 *s = 0;
1070         else {
1071                 r = parse_bytes(rvalue, s);
1072                 if (r < 0)
1073                         return r;
1074         }
1075
1076         return 0;
1077 }
1078
1079 int config_parse_strv(const char *filename,
1080                       unsigned line,
1081                       const char *section,
1082                       const char *lvalue,
1083                       int ltype,
1084                       const char *rvalue,
1085                       void *data)
1086 {
1087         char ***strv = data;
1088         char **o = NULL, **v = NULL, **vv = NULL;
1089         int r;
1090
1091         assert(filename);
1092         assert(lvalue);
1093         assert(rvalue);
1094         assert(data);
1095
1096         if (is_empty(rvalue))
1097                 return 0;
1098
1099         r = str_to_strv(rvalue, &v, WHITESPACE);
1100         if (r < 0)
1101                 return r;
1102
1103         o = *strv;
1104
1105         r = strv_attach(o, v, &vv, true);
1106         if (r < 0)
1107                 return r;
1108
1109         *strv = vv;
1110
1111         return 0;
1112 }