2
* Copyright (C) 2002,2003,2004 Mattia Dongili<dongili@supereva.it>
3
* George Staikos <staikos@0wned.org>
6
* - added percentage/absolute frequency translation based on a patch submitted
10
* - added support for cpu monitoring, base code by Dietz Proepper and minor
11
* fixes by Mattia Dongili
13
* This program is free software; you can redistribute it and/or modify
14
* it under the terms of the GNU General Public License as published by
15
* the Free Software Foundation; either version 2 of the License, or
16
* (at your option) any later version.
18
* This program is distributed in the hope that it will be useful,
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
* GNU General Public License for more details.
23
* You should have received a copy of the GNU General Public License
24
* along with this program; if not, write to the Free Software
25
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30
#include "config_parser.h"
33
* Parse configuration file.
35
* As long as the config file is quite simple let's keep also a veryvery simple parser.
37
int parse_config (general *g) {
39
profile *last_profile = 0L, *p_iter = 0L;
40
rule *last_rule = 0L, *r_iter = 0L;
43
/* configuration file */
44
cp_log(LOG_INFO, "parse_config(): reading configuration file %s\n", g->config_file);
45
config = fopen(g->config_file, "r");
47
cp_log(LOG_ERR, "parse_config(): %s: %s\n", g->config_file, strerror(errno));
51
while (!feof(config)) {
54
if (!fgets(buf, 255, config))
57
clean = clean_config_line(buf);
59
if (!clean[0]) /* returned an empty line */
62
clean = strip_comments_line(clean);
64
if (!clean[0]) /* returned an empty line */
67
/* if General scan general options */
68
if (strstr(clean,"[General]")) {
69
if (parse_config_general (config, g) < 0) {
75
/* if Profile scan profile options */
76
if (strstr(clean,"[Profile]")) {
78
profile *prof = (profile *)malloc(sizeof(profile));
79
memset(prof, 0, sizeof(profile));
80
if (parse_config_profile (config, prof, g) < 0) {
81
cp_log(LOG_CRIT, "parse_config(): [Profile] error parsing %s, see logs for details.\n", g->config_file);
86
g->profiles = last_profile = prof;
89
/* checks duplicate names */
91
if (strcmp(p_iter->name, prof->name) == 0) {
92
cp_log(LOG_CRIT, "parse_config(): [Profile] name \"%s\" already exists.\n", prof->name);
96
p_iter = p_iter->next;
98
last_profile->next = prof;
99
last_profile = last_profile->next;
104
/* if Rule scan rules options */
105
if (strstr(clean,"[Rule]")) {
106
rule *rul = (rule *)malloc(sizeof(rule));
107
memset(rul, 0, sizeof(rule));
108
if (parse_config_rule (config, rul) < 0) {
109
cp_log(LOG_CRIT, "parse_config(): [Rule] error parsing %s, see logs for details.\n", g->config_file);
113
g->rules = last_rule = rul;
116
/* check duplicate names */
117
while (r_iter != NULL) {
118
if (strcmp(r_iter->name, rul->name) == 0) {
119
cp_log(LOG_CRIT, "parse_config(): [Rule] name \"%s\" already exists.\n", rul->name);
122
r_iter = r_iter->next;
124
last_rule->next = rul;
125
last_rule = last_rule->next;
133
/* did I read something?
134
* chek if I read at least one rule, otherwise exit
136
if (g->rules == NULL) {
137
cp_log(LOG_ERR, "parse_config(): No rules found!\n");
142
* associate rules->profiles
143
* go through rules and associate to the proper profile
146
while (r_iter != NULL) {
147
int profile_found = 0;
149
p_iter = g->profiles;
150
/* go through profiles */
151
while (p_iter != NULL) {
152
if (strcmp(r_iter->profile_name, p_iter->name)==0) {
153
/* a profile is allowed to be addressed by more than 1 rule */
154
r_iter->prof = p_iter;
158
p_iter = p_iter->next;
161
if (!profile_found) {
162
cp_log(LOG_CRIT, "parse_config(): Syntax error: no Profile section found for Rule \"%s\" \
163
(requested Profile \"%s\")\n",
165
r_iter->profile_name);
168
r_iter = r_iter->next;
172
while (r_iter != NULL) {
173
cp_log(LOG_NOTICE, "parse_config(): Rule \"%s\" has Profile \"%s\"\n", r_iter->name, r_iter->prof->name);
174
r_iter = r_iter->next;
181
* parse the [General] section
183
* Returns -1 if required properties are missing, 0 otherwise
185
int parse_config_general (FILE *config, general *g) {
188
while (!feof(config)) {
193
if (!fgets(buf, 255, config))
196
clean = strip_comments_line(buf);
198
if (!clean[0]) /* returned an empty line */
201
clean = clean_config_line(clean);
203
if (!clean[0]) /* returned an empty line */
206
name = strtok(clean, "=");
207
value = strtok(NULL, "");
209
if (strcmp(name,"poll_interval") == 0) {
211
g->poll_interval = atoi (value);
214
if (g->poll_interval < 1) {
215
cp_log(LOG_WARNING, "WARNING: [General] poll_interval has invalid value, using default.\n");
216
g->poll_interval = DEFAULT_POLL;
218
} else if (strcmp(name,"verbosity") == 0) {
219
if (!g->log_level_overridden) {
221
g->log_level = atoi (value);
223
if (g->log_level < 0 || g->log_level > 7) {
224
cp_log(LOG_WARNING, "WARNING: [General] verbosity has invalid value, using default (%d).\n", DEFAULT_VERBOSITY);
225
g->log_level = DEFAULT_VERBOSITY;
228
g->log_level = DEFAULT_VERBOSITY;
229
cp_log(LOG_WARNING, "WARNING: [General] verbosity has empty value, using default (%d).\n", DEFAULT_VERBOSITY);
232
cp_log(LOG_DEBUG, "parse_config_general(): skipping \"verbosity\", overridden in the command line.\n");
234
} else if (strcmp(name,"pm_type") == 0) {
236
strncpy(g->pm_plugin, value, 101);
238
cp_log(LOG_WARNING, "parse_config_general(): empty \"pm_type\", using default "DEFAULT_PMPLUGIN".\n");
239
strncpy(g->pm_plugin, DEFAULT_PMPLUGIN, 101);
241
g->pm_plugin[100] = 0;
242
} else if (strcmp(name,"pidfile") == 0) {
244
strncpy(g->pidfile, value, 512);
246
cp_log(LOG_WARNING, "parse_config_general(): empty \"pidfile\", using default "CPUFREQD_PIDFILE".\n");
247
strncpy(g->pidfile, CPUFREQD_PIDFILE, 512);
250
} else if (strcmp(name,"acpi_workaround") == 0) {
252
g->acpi_workaround = atoi (value);
253
cp_log(LOG_WARNING, "parse_config_general(): ACPI workaround enabled.\n");
256
cp_log(LOG_WARNING, "WARNING: [General] skipping unknown config option \"%s\"\n", name);
264
* parse a [Profile] section
266
* Returns -1 if required properties are missing, 0 otherwise
268
int parse_config_profile (FILE *config, profile *p, general *g) {
276
while (!feof(config)) {
281
if (!fgets(buf, 255, config))
284
clean = strip_comments_line(buf);
286
if (!clean[0]) /* returned an empty line */
289
clean = clean_config_line(clean);
291
if (!clean[0]) /* returned an empty line */
294
name = strtok(clean, "=");
295
value = strtok(NULL, "");
297
/* empty value: skip */
301
if (strcmp(name,"name")==0) {
302
strncpy(p->name, value, 255);
305
} else if (strcmp(name,"minfreq")==0) {
306
if (strstr(value, "%") != NULL) {
307
/* set separator (useful for 2.4 kernels only) */
311
cp_log(LOG_CRIT, "parse_config_profile(): cannot mix percentage and absolute kHz values in a single profile.\n");
315
/* set separator (useful for 2.4 kernels only) */
319
cp_log(LOG_CRIT, "parse_config_profile(): cannot mix percentage and absolute kHz values in a single profile.\n");
323
p->min_freq = atol(value);
326
} else if (strcmp(name,"maxfreq") == 0) {
328
if (strstr(value, "%") != NULL) {
329
/* set separator (useful for 2.4 kernels only) */
333
cp_log(LOG_CRIT, "parse_config_profile(): cannot mix percentage and absolute kHz values in a single profile.\n");
337
/* set separator (useful for 2.4 kernels only) */
341
cp_log(LOG_CRIT, "parse_config_profile(): cannot mix percentage and absolute kHz values in a single profile.\n");
345
p->max_freq = atol(value);
348
} else if (strcmp(name,"policy") == 0) {
350
strncpy(p->policy_name, value, 255);
351
p->policy_name[254] = 0;
355
cp_log(LOG_WARNING, "WARNING: [Profile] skipping unknown config option \"%s\"\n", name);
359
if (!(state & HAS_NAME)) {
360
cp_log(LOG_ERR, "parse_config_profile(): [Profile] missing required property \"name\".\n");
363
if (!(state & HAS_MIN)) {
364
cp_log(LOG_ERR, "parse_config_profile(): [Profile] \"%s\" missing required property \"minfreq\".\n", p->name);
367
if (!(state & HAS_MAX)) {
368
cp_log(LOG_ERR, "parse_config_profile(): [Profile] \"%s\" missing required property \"maxfreq\".\n", p->name);
371
if (!(state & HAS_POLICY)) {
372
cp_log(LOG_ERR, "parse_config_profile(): [Profile] \"%s\" missing required property \"policy\".\n", p->name);
376
/* translate max_freq to absolute value if necessary */
377
if (g->has_sysfs && p->sep == '%') {
378
p->max_freq = g->cpu_max_freq * ((float)p->max_freq / 100);
379
cp_log(LOG_INFO, "parse_config_profile(): [Profile] \"%s\" translated max frequency to %d\n", p->name, p->max_freq);
380
/* normalize if necessary */
381
if (p->max_freq > g->cpu_max_freq) {
382
cp_log(LOG_NOTICE, "parse_config_profile(): [Profile] \"%s\" max frequency %d out of range\n", p->name, p->max_freq);
383
p->max_freq = g->cpu_max_freq;
386
/* translate min_freq to absolute value if necessary */
387
if (g->has_sysfs && p->sep == '%') {
388
p->min_freq = g->cpu_max_freq * ((float)p->min_freq / 100);
389
cp_log(LOG_INFO, "parse_config_profile(): [Profile] \"%s\" translated min frequency to %d\n", p->name, p->min_freq);
390
/* normalize if necessary */
391
if (p->min_freq < g->cpu_min_freq) {
392
cp_log(LOG_NOTICE, "parse_config_profile(): [Profile] \"%s\" min frequency %d out of range\n", p->name, p->min_freq);
393
p->min_freq = g->cpu_min_freq;
401
* parses a [Rule] section
403
* Returns -1 if required properties are missing, 0 otherwise
405
int parse_config_rule (FILE *config, rule *r) {
407
#define HAS_PROFILE 2
411
/* reset profile ref */
414
/* initialize battery_interval */
415
r->bat = (battery_interval *) malloc(sizeof(battery_interval));
419
/* initialize cpu_interval */
420
r->cpu = (cpu_interval *) malloc(sizeof(cpu_interval));
421
r->cpu->min = 101; /* so we won't ever trigger them... */
424
/* initialize cpu_nice_scale to DEFAULT_NICE_SCALE */
425
r->cpu_nice_scale = DEFAULT_NICE_SCALE;
427
while (!feof(config)) {
432
if (!fgets(buf, 255, config))
435
clean = strip_comments_line(buf);
437
if (!clean[0]) /* returned an empty line */
440
clean = clean_config_line(clean);
442
if (!clean[0]) /* returned an empty line */
445
name = strtok(clean, "=");
446
value = strtok(NULL, "");
448
/* empty value: skip */
452
if (strcmp(name,"name") == 0) {
453
strncpy(r->name, value, 255);
456
} else if (strcmp(name,"ac") == 0) {
457
r->ac = strcmp(value,"on") == 0 ? 1:0;
458
} else if (strcmp(name,"battery_interval") == 0) {
459
r->bat->min = atoi(strtok(value,"-"));
460
r->bat->max = atoi(strtok(NULL,""));
461
} else if (strcmp(name,"cpu_interval") == 0) {
462
r->cpu->min = atoi(strtok(value,"-"));
463
r->cpu->max = atoi(strtok(NULL,""));
464
} else if (strcmp(name,"cpu_nice_scale") == 0) {
465
r->cpu_nice_scale = atof(value);
466
if (r->cpu_nice_scale<=0) {
467
cp_log(LOG_ERR, "parse_config_rule(): [Rule] invalid \"cpu_nice_scale\" value: %f.\n", r->cpu_nice_scale);
470
} else if (strcmp(name,"delay_cycles") == 0) {
471
r->delay_cycles = atoi(value);
472
if (r->delay_cycles<0) {
473
cp_log(LOG_ERR, "parse_config_rule(): [Rule] invalid \"delay_cycles\" value: %d.\n", r->delay_cycles);
476
} else if (strcmp(name,"programs") == 0) {
477
/* create program list */
479
r->program_list = string_list_new();
480
t_prog = strtok(value,",");
482
struct string_node *temp;
487
temp = string_node_new();
488
strncpy(temp->string, t_prog, 255);
489
temp->string[254] = 0;
491
string_list_append(r->program_list, temp);
492
cp_log(LOG_DEBUG, "parse_config_rule(): read program: %s\n", temp->string);
493
} while ((t_prog = strtok(NULL,",")) != NULL);
495
} else if (strcmp(name, "profile") == 0) {
496
strncpy(r->profile_name, value, 255);
497
r->profile_name[254] = 0;
498
state |= HAS_PROFILE;
500
cp_log(LOG_WARNING, "WARNING: [Rule] skipping unknown config option \"%s\"\n", name);
504
if (!(state & HAS_NAME)) {
505
cp_log(LOG_ERR, "parse_config_rule(): [Rule] missing required property \"name\".\n");
509
if (!(state & HAS_PROFILE)) {
510
cp_log(LOG_ERR, "parse_config_rule(): [Rule] \"%s\" missing required property \"profile\".\n",
518
/* char *clean_config_line (char *str)
520
* Removes trailing blanks and CR off the string str
522
* Returns a pointer to the cleaned string.
523
* WARNING: it modifies the input string!
526
char *clean_config_line (char *str) {
529
/* remove white spaces at the beginning */
530
while (isspace(str[0])) {
534
/* remove end line white space */
536
while (i >= 0 && isspace(str[i])) {
544
/* char *strip_comments_line (char *str)
546
* Removes comments off the string str
548
* Returns a pointer to the cleaned string.
549
* WARNING: it modifies the input string!
552
char *strip_comments_line (char *str) {
556
for (i = strlen(str); i >= 0; i--) {
565
/* void free_config(general *g)
567
* Frees the structures allocated.
570
void free_config(general *g) {
571
profile *p_iter = 0L, *p_temp = 0L;
572
rule *r_iter = 0L, *r_temp = 0L;
574
/* cleanup config structs */
576
while (r_iter != NULL) {
578
r_iter = r_iter->next;
580
cp_log(LOG_DEBUG, "free_config(): freeing rule %s.\n", r_temp->name);
581
cp_log(LOG_DEBUG, "free_config(): freeing battery interval %d-%d.\n", r_temp->bat->min, r_temp->bat->max);
585
cp_log(LOG_DEBUG, "free_config(): freeing cpu interval %d-%d.\n", r_temp->cpu->min, r_temp->cpu->max);
591
cp_log(LOG_DEBUG, "free_config(): freeing program list.\n");
593
if (r_temp->program_list) {
594
string_list_free_sublist(r_temp->program_list, r_temp->program_list->first);
595
free(r_temp->program_list);
602
p_iter = g->profiles;
603
while (p_iter != NULL) {
605
p_iter = p_iter->next;
606
cp_log(LOG_DEBUG, "free_config(): freeing profile %s.\n", p_temp->name);
611
/* clean other values */
612
g->poll_interval = DEFAULT_POLL;
614
g->acpi_workaround = 0;
618
if (!g->log_level_overridden)
619
g->log_level = DEFAULT_VERBOSITY;