1 #define MODULE_LOG_PREFIX "config"
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
;
40 cs_strncpy(varnamebuf
, varname
, sizeof(varnamebuf
));
41 while(varlen
< CONFVARWIDTH
)
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
);
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
)
66 if(strcasecmp(token
, c
->config_name
) != 0)
68 void *var
= config_data
+ c
->var_offset
;
73 *(int8_t *)var
= (int8_t)strToIntVal(value
, c
->def
.d_int8
);
78 uint32_t tmp
= strToUIntVal(value
, c
->def
.d_uint8
);
79 *(uint8_t *)var
= (uint8_t)(tmp
<= 0xff ? tmp
: 0xff);
84 int32_t tmp
= strToIntVal(value
, c
->def
.d_int32
);
85 memcpy(var
, &tmp
, sizeof(int32_t));
90 uint32_t tmp
= strToUIntVal(value
, c
->def
.d_uint32
);
91 memcpy(var
, &tmp
, sizeof(uint32_t));
97 if(c
->def
.d_char
&& cs_strlen(value
) == 0) // Set default
98 { value
= c
->def
.d_char
; }
101 { *scfg
= cs_strdup(value
); }
107 if(c
->def
.d_char
&& cs_strlen(value
) == 0) // Set default
108 { value
= c
->def
.d_char
; }
110 unsigned int len
= cs_strlen(value
);
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
);
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);
137 c
->ops
.process_fn(token
, value
, var
, NULL
);
142 c
->ops
.process_fn_extra(token
, value
, var
, c
->def
.d_extra
, NULL
);
150 fprintf(stderr
, "Unknown config type (%s = %s).", token
, value
);
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
))
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
); }
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
); }
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
); }
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
); }
207 if(save_all
|| !streq(*val
, c
->def
.d_char
))
209 fprintf_conf(f
, c
->config_name
, "%s\n", *val
? *val
: "");
216 if(save_all
|| !streq(val
, c
->def
.d_char
))
218 fprintf_conf(f
, c
->config_name
, "%s\n", val
[0] ? val
: "");
224 uint8_t *hex_array
= var
;
225 uint32_t ok
= array_has_nonzero_byte(hex_array
, c
->def
.array_size
);
228 fprintf_conf(f
, c
->config_name
, "%s", ""); // it should not have \n at the end
231 for(ok
= 0; ok
< c
->def
.array_size
; ok
++)
233 fprintf(f
, "%02X", hex_array
[ok
]);
242 c
->ops
.process_fn((const char *)c
->config_name
, NULL
, var
, f
);
247 c
->ops
.process_fn_extra((const char *)c
->config_name
, NULL
, var
, c
->def
.d_extra
, f
);
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
);
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
);
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
;
295 *(int8_t *)var
= c
->def
.d_int8
;
300 *(uint8_t *)var
= c
->def
.d_uint8
;
305 memcpy(var
, &c
->def
.d_int32
, sizeof(int32_t));
310 memcpy(var
, &c
->def
.d_uint32
, sizeof(uint32_t));
318 { *scfg
= cs_strdup(c
->def
.d_char
); }
325 if(c
->def
.d_char
&& cs_strlen(c
->def
.d_char
))
326 { cs_strncpy(scfg
, c
->def
.d_char
, c
->str_size
); }
331 uint8_t *hex_array
= var
;
332 memset(hex_array
, 0, c
->def
.array_size
);
337 c
->ops
.process_fn((const char *)c
->config_name
, "", var
, NULL
);
342 c
->ops
.process_fn_extra((const char *)c
->config_name
, "", var
, c
->def
.d_extra
, NULL
);
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
)
365 if(c
->free_value
&& (c
->opt_type
== OPT_FUNC
|| c
->opt_type
== OPT_FUNC_EXTRA
))
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
)
388 int config_section_is_active(const struct config_sections
*sec
)
392 if(sec
->config
[0].opt_type
== OPT_UNKNOWN
)
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
))
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
);
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
);
452 fprintf(stderr
, "WARNING: Unknown section '%s'.\n", section
);
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
);
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
)
472 FILE *f
= fopen(get_config_filename(filename
, sizeof(filename
), conf_filename
), "r");
477 fprintf(stderr
, "ERROR: Cannot open file \"%s\" (errno=%d %s)", filename
, errno
, strerror(errno
));
478 fprintf(stderr
, "\n");
483 cs_log_dbg(D_TRACE
, "INFO: Cannot open file \"%s\" (errno=%d %s)", filename
, errno
, strerror(errno
));
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
)
504 get_config_filename(temp_file
, sizeof(temp_file
), conf_filename
);
505 if (!cs_strncat(temp_file
, ".tmp", sizeof(temp_file
))) {
508 FILE *f
= fopen(temp_file
, "w");
511 cs_log("ERROR: Cannot create file \"%s\" (errno=%d %s)", temp_file
, errno
, strerror(errno
));
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",
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);
533 return safe_overwrite_with_bak(dst_file
, tmp_file
, bak_file
, cfg
.http_overwrite_bak_file
);