- fix Building without Nagra not possible at Nagra_Merlin https://trac.streamboard...
[oscam.git] / oscam-conf.c
blobe25aba18a95f15756cb70626420158b80774e440
1 #define MODULE_LOG_PREFIX "config"
3 #include "globals.h"
4 #include "oscam-conf.h"
5 #include "oscam-config.h"
6 #include "oscam-files.h"
7 #include "oscam-garbage.h"
8 #include "oscam-string.h"
10 #define CONFVARWIDTH 30
12 /* Returns the default value if string length is zero, otherwise atoi is called*/
13 int32_t strToIntVal(char *value, int32_t defaultvalue)
15 if(cs_strlen(value) == 0) { return defaultvalue; }
16 errno = 0; // errno should be set to 0 before calling strtol
17 int32_t i = strtol(value, NULL, 10);
18 return (errno == 0) ? i : defaultvalue;
21 /* Returns the default value if string length is zero, otherwise strtoul is called*/
22 uint32_t strToUIntVal(char *value, uint32_t defaultvalue)
24 if(cs_strlen(value) == 0) { return defaultvalue; }
25 errno = 0; // errno should be set to 0 before calling strtoul
26 uint32_t i = strtoul(value, NULL, 10);
27 return (errno == 0) ? i : defaultvalue;
30 /* Replacement of fprintf which adds necessary whitespace to fill up the varname to a fixed width.
31 If varname is longer than CONFVARWIDTH, no whitespace is added*/
32 void fprintf_conf(FILE *f, const char *varname, const char *fmtstring, ...)
34 int32_t varlen = cs_strlen(varname);
35 int32_t max = (varlen > CONFVARWIDTH) ? varlen : CONFVARWIDTH;
36 char varnamebuf[max + 3];
37 char *ptr = varnamebuf + varlen;
38 va_list argptr;
40 cs_strncpy(varnamebuf, varname, sizeof(varnamebuf));
41 while(varlen < CONFVARWIDTH)
43 ptr[0] = ' ';
44 ++ptr;
45 ++varlen;
47 cs_strncpy(ptr, "= ", sizeof(varnamebuf) - (ptr - varnamebuf));
48 if(fwrite(varnamebuf, sizeof(char), cs_strlen(varnamebuf), f))
50 if(cs_strlen(fmtstring) > 0)
52 va_start(argptr, fmtstring);
53 vfprintf(f, fmtstring, argptr);
54 va_end(argptr);
59 int config_list_parse(const struct config_list *clist, const char *token, char *value, void *config_data)
61 const struct config_list *c;
62 for(c = clist; c->opt_type != OPT_UNKNOWN; c++)
64 if(c->opt_type == OPT_SAVE_FUNC || c->opt_type == OPT_FIXUP_FUNC)
65 { continue; }
66 if(strcasecmp(token, c->config_name) != 0)
67 { continue; }
68 void *var = config_data + c->var_offset;
69 switch(c->opt_type)
71 case OPT_INT8:
73 *(int8_t *)var = (int8_t)strToIntVal(value, c->def.d_int8);
74 return 1;
76 case OPT_UINT8:
78 uint32_t tmp = strToUIntVal(value, c->def.d_uint8);
79 *(uint8_t *)var = (uint8_t)(tmp <= 0xff ? tmp : 0xff);
80 return 1;
82 case OPT_INT32:
84 int32_t tmp = strToIntVal(value, c->def.d_int32);
85 memcpy(var, &tmp, sizeof(int32_t));
86 return 1;
88 case OPT_UINT32:
90 uint32_t tmp = strToUIntVal(value, c->def.d_uint32);
91 memcpy(var, &tmp, sizeof(uint32_t));
92 return 1;
94 case OPT_STRING:
96 char **scfg = var;
97 if(c->def.d_char && cs_strlen(value) == 0) // Set default
98 { value = c->def.d_char; }
99 NULLFREE(*scfg);
100 if(cs_strlen(value))
101 { *scfg = cs_strdup(value); }
102 return 1;
104 case OPT_SSTRING:
106 char *scfg = var;
107 if(c->def.d_char && cs_strlen(value) == 0) // Set default
108 { value = c->def.d_char; }
109 scfg[0] = '\0';
110 unsigned int len = cs_strlen(value);
111 if(len)
113 cs_strncpy(scfg, value, c->str_size);
114 if(len > c->str_size)
116 fprintf(stderr, "WARNING: Config value for '%s' (%s, len=%u) exceeds max length: %d (%s)\n",
117 token, value, len, c->str_size - 1, scfg);
120 return 1;
122 case OPT_HEX_ARRAY:
124 uint8_t *hex_array = var;
125 if(!cs_strlen(value))
126 { memset(hex_array, 0, c->def.array_size); }
127 else if(key_atob_l(value, hex_array, c->def.array_size * 2))
129 memset(hex_array, 0, c->def.array_size);
130 fprintf(stderr, "WARNING: Config value for '%s' (%s, len=%zu) requires %d chars.\n",
131 token, value, cs_strlen(value), c->def.array_size * 2);
133 return 1;
135 case OPT_FUNC:
137 c->ops.process_fn(token, value, var, NULL);
138 return 1;
140 case OPT_FUNC_EXTRA:
142 c->ops.process_fn_extra(token, value, var, c->def.d_extra, NULL);
143 return 1;
145 case OPT_FIXUP_FUNC:
146 case OPT_SAVE_FUNC:
147 return 1;
148 case OPT_UNKNOWN:
150 fprintf(stderr, "Unknown config type (%s = %s).", token, value);
151 break;
155 return 0;
158 void config_list_save_ex(FILE *f, const struct config_list *clist, void *config_data, int save_all,
159 bool (*check_func)(const struct config_list *clist, void *config_data, const char *setting))
161 const struct config_list *c;
162 for(c = clist; c->opt_type != OPT_UNKNOWN; c++)
164 void *var = config_data + c->var_offset;
165 if(check_func && c->opt_type != OPT_UNKNOWN)
167 if(!check_func(clist, config_data, c->config_name))
168 { continue; }
170 switch(c->opt_type)
172 case OPT_INT8:
174 int8_t val = *(int8_t *)var;
176 // always save pmt_mode, because external tools parse it
177 if(save_all || val != c->def.d_int8 || !strcmp(c->config_name, "pmt_mode"))
178 { fprintf_conf(f, c->config_name, "%d\n", val); }
179 continue;
181 case OPT_UINT8:
183 uint8_t val = *(uint8_t *)var;
184 if(save_all || val != c->def.d_uint8)
185 { fprintf_conf(f, c->config_name, "%u\n", val); }
186 continue;
188 case OPT_INT32:
190 int32_t val;
191 memcpy(&val, var, sizeof(int32_t));
192 if(save_all || val != c->def.d_int32)
193 { fprintf_conf(f, c->config_name, "%d\n", val); }
194 continue;
196 case OPT_UINT32:
198 uint32_t val;
199 memcpy(&val, var, sizeof(uint32_t));
200 if(save_all || val != c->def.d_uint32)
201 { fprintf_conf(f, c->config_name, "%u\n", val); }
202 continue;
204 case OPT_STRING:
206 char **val = var;
207 if(save_all || !streq(*val, c->def.d_char))
209 fprintf_conf(f, c->config_name, "%s\n", *val ? *val : "");
211 continue;
213 case OPT_SSTRING:
215 char *val = var;
216 if(save_all || !streq(val, c->def.d_char))
218 fprintf_conf(f, c->config_name, "%s\n", val[0] ? val : "");
220 continue;
222 case OPT_HEX_ARRAY:
224 uint8_t *hex_array = var;
225 uint32_t ok = array_has_nonzero_byte(hex_array, c->def.array_size);
226 if(save_all || ok)
228 fprintf_conf(f, c->config_name, "%s", ""); // it should not have \n at the end
229 if(ok)
231 for(ok = 0; ok < c->def.array_size; ok++)
233 fprintf(f, "%02X", hex_array[ok]);
236 fprintf(f, "\n");
238 continue;
240 case OPT_FUNC:
242 c->ops.process_fn((const char *)c->config_name, NULL, var, f);
243 continue;
245 case OPT_FUNC_EXTRA:
247 c->ops.process_fn_extra((const char *)c->config_name, NULL, var, c->def.d_extra, f);
248 continue;
250 case OPT_FIXUP_FUNC:
251 case OPT_SAVE_FUNC:
252 continue;
253 case OPT_UNKNOWN:
254 break;
259 bool config_list_should_be_saved(const struct config_list *clist, void *var)
261 const struct config_list *c;
262 for(c = clist; c->opt_type != OPT_UNKNOWN; c++)
264 if(c->opt_type == OPT_SAVE_FUNC)
266 return c->ops.should_save_fn(var);
269 return true;
272 void config_list_apply_fixups(const struct config_list *clist, void *var)
274 const struct config_list *c;
275 for(c = clist; c->opt_type != OPT_UNKNOWN; c++)
277 if(c->opt_type == OPT_FIXUP_FUNC)
279 c->ops.fixup_fn(var);
280 break;
285 void config_list_set_defaults(const struct config_list *clist, void *config_data)
287 const struct config_list *c;
288 for(c = clist; c->opt_type != OPT_UNKNOWN; c++)
290 void *var = config_data + c->var_offset;
291 switch(c->opt_type)
293 case OPT_INT8:
295 *(int8_t *)var = c->def.d_int8;
296 break;
298 case OPT_UINT8:
300 *(uint8_t *)var = c->def.d_uint8;
301 break;
303 case OPT_INT32:
305 memcpy(var, &c->def.d_int32, sizeof(int32_t));
306 break;
308 case OPT_UINT32:
310 memcpy(var, &c->def.d_uint32, sizeof(uint32_t));
311 break;
313 case OPT_STRING:
315 char **scfg = var;
316 NULLFREE(*scfg);
317 if(c->def.d_char)
318 { *scfg = cs_strdup(c->def.d_char); }
319 break;
321 case OPT_SSTRING:
323 char *scfg = var;
324 scfg[0] = '\0';
325 if(c->def.d_char && cs_strlen(c->def.d_char))
326 { cs_strncpy(scfg, c->def.d_char, c->str_size); }
327 break;
329 case OPT_HEX_ARRAY:
331 uint8_t *hex_array = var;
332 memset(hex_array, 0, c->def.array_size);
333 break;
335 case OPT_FUNC:
337 c->ops.process_fn((const char *)c->config_name, "", var, NULL);
338 break;
340 case OPT_FUNC_EXTRA:
342 c->ops.process_fn_extra((const char *)c->config_name, "", var, c->def.d_extra, NULL);
343 break;
345 case OPT_SAVE_FUNC:
346 case OPT_FIXUP_FUNC:
347 case OPT_UNKNOWN:
348 continue;
351 return;
354 void config_list_free_values(const struct config_list *clist, void *config_data)
356 const struct config_list *c;
357 for(c = clist; c->opt_type != OPT_UNKNOWN; c++)
359 void *var = config_data + c->var_offset;
360 if(c->opt_type == OPT_STRING)
362 char **scfg = var;
363 NULLFREE(*scfg);
365 if(c->free_value && (c->opt_type == OPT_FUNC || c->opt_type == OPT_FUNC_EXTRA))
367 c->free_value(var);
370 return;
373 void config_list_gc_values(const struct config_list *clist, void *config_data)
375 const struct config_list *c;
376 for(c = clist; c->opt_type != OPT_UNKNOWN; c++)
378 void *var = config_data + c->var_offset;
379 if(c->opt_type == OPT_STRING)
381 char **scfg = var;
382 add_garbage(*scfg);
385 return;
388 int config_section_is_active(const struct config_sections *sec)
390 if(!sec)
391 { return 0; }
392 if(sec->config[0].opt_type == OPT_UNKNOWN)
393 { return 0; }
394 return 1;
397 const struct config_sections *config_find_section(const struct config_sections *conf, char *section_name)
399 const struct config_sections *sec;
400 for(sec = conf; sec && sec->section; sec++)
402 if(streq(section_name, sec->section))
404 return sec;
407 return NULL;
410 void config_sections_save(const struct config_sections *conf, FILE *f, void *var)
412 const struct config_sections *sec;
413 for(sec = conf; sec && sec->section; sec++)
415 if(config_section_is_active(sec) && config_list_should_be_saved(sec->config, var))
417 fprintf(f, "[%s]\n", sec->section);
418 config_list_apply_fixups(sec->config, var);
419 config_list_save(f, sec->config, var, cfg.http_full_cfg);
420 fprintf(f, "\n");
425 void config_sections_set_defaults(const struct config_sections *conf, void *var)
427 const struct config_sections *sec;
428 for(sec = conf; sec && sec->section; sec++)
430 if(config_section_is_active(sec))
431 { config_list_set_defaults(sec->config, var); }
435 void config_sections_free(const struct config_sections *conf, void *var)
437 const struct config_sections *sec;
438 for(sec = conf; sec && sec->section; sec++)
440 if(config_section_is_active(sec))
442 config_list_free_values(sec->config, var);
447 void config_set_value(const struct config_sections *conf, char *section, const char *token, char *value, void *var)
449 const struct config_sections *sec = config_find_section(conf, section);
450 if(!sec)
452 fprintf(stderr, "WARNING: Unknown section '%s'.\n", section);
453 return;
455 if(config_section_is_active(sec))
457 if(!config_list_parse(sec->config, token, value, var))
459 fprintf(stderr, "WARNING: In section [%s] unknown setting '%s=%s' tried.\n",
460 section, token, value);
463 else
465 fprintf(stderr, "WARNING: Section is not active '%s'.\n", section);
469 static FILE *__open_config_file(const char *conf_filename, bool die_on_err)
471 char filename[256];
472 FILE *f = fopen(get_config_filename(filename, sizeof(filename), conf_filename), "r");
473 if(!f)
475 if(die_on_err)
477 fprintf(stderr, "ERROR: Cannot open file \"%s\" (errno=%d %s)", filename, errno, strerror(errno));
478 fprintf(stderr, "\n");
479 exit(1);
481 else
483 cs_log_dbg(D_TRACE, "INFO: Cannot open file \"%s\" (errno=%d %s)", filename, errno, strerror(errno));
485 return NULL;
487 return f;
490 FILE *open_config_file(const char *conf_filename)
492 return __open_config_file(conf_filename, false);
495 FILE *open_config_file_or_die(const char *conf_filename)
497 return __open_config_file(conf_filename, true);
501 FILE *create_config_file(const char *conf_filename)
503 char temp_file[256];
504 get_config_filename(temp_file, sizeof(temp_file), conf_filename);
505 if (!cs_strncat(temp_file, ".tmp", sizeof(temp_file))) {
506 return NULL;
508 FILE *f = fopen(temp_file, "w");
509 if(!f)
511 cs_log("ERROR: Cannot create file \"%s\" (errno=%d %s)", temp_file, errno, strerror(errno));
512 return NULL;
514 fprintf(f, "# %s generated automatically by Streamboard OSCAM %s SVN r%s\n",
515 conf_filename, CS_VERSION, CS_SVN_VERSION);
516 fprintf(f, "# Read more: https://svn.streamboard.tv/oscam/trunk/Distribution/doc/txt/%s.txt\n\n",
517 conf_filename);
518 return f;
521 bool flush_config_file(FILE *f, const char *conf_filename)
523 char dst_file[256], tmp_file[256], bak_file[256];
524 get_config_filename(dst_file, sizeof(dst_file), conf_filename);
525 memcpy(tmp_file, dst_file, sizeof(tmp_file));
526 memcpy(bak_file, dst_file, sizeof(bak_file));
527 strncat(tmp_file, ".tmp", sizeof(tmp_file) - cs_strlen(tmp_file) - 1);
528 strncat(bak_file, ".bak", sizeof(bak_file) - cs_strlen(bak_file) - 1);
529 if(f)
531 fclose(f);
533 return safe_overwrite_with_bak(dst_file, tmp_file, bak_file, cfg.http_overwrite_bak_file);