use individual files for storing configuration. This is not so error prone.

Also, use a better naming scheme for DVB adapters (adapter vendor name + a sequence id)
This commit is contained in:
Andreas Öman 2008-01-28 20:40:35 +00:00
parent aba7e9b779
commit 6177fec24c
9 changed files with 258 additions and 92 deletions

View file

@ -27,6 +27,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <libhts/htscfg.h>
@ -38,6 +39,9 @@
#include "channels.h"
#include "transports.h"
static void channel_group_settings_write(void);
static void channel_settings_write(th_channel_t *ch);
struct th_channel_list channels;
struct th_transport_list all_transports;
int nchannels;
@ -46,7 +50,6 @@ struct th_channel_group_queue all_channel_groups;
th_channel_group_t *defgroup;
static int dontwritesettings;
void scanner_init(void);
@ -112,8 +115,7 @@ channel_group_find(const char *name, int create)
TAILQ_INSERT_TAIL(&all_channel_groups, tcg, tcg_global_link);
channel_settings_write();
channel_group_settings_write();
return tcg;
}
@ -131,7 +133,18 @@ channel_set_group(th_channel_t *ch, th_channel_group_t *tcg)
ch->ch_group = tcg;
TAILQ_INSERT_SORTED(&tcg->tcg_channels, ch, ch_group_link, channelcmp);
channel_settings_write();
channel_settings_write(ch);
}
/**
*
*/
void
channel_set_teletext_rundown(th_channel_t *ch, int v)
{
ch->ch_teletext_rundown = v;
channel_settings_write(ch);
}
/**
@ -152,6 +165,8 @@ channel_group_destroy(th_channel_group_t *tcg)
TAILQ_REMOVE(&all_channel_groups, tcg, tcg_global_link);
free((void *)tcg->tcg_name);
free(tcg);
channel_group_settings_write();
}
/**
@ -241,54 +256,80 @@ service_load(struct config_head *head)
void
channels_load(void)
{
config_entry_t *ce, *ce1, *ce2;
const char *name;
th_channel_group_t *tcg;
struct config_head cl;
config_entry_t *ce;
char buf[400];
DIR *dir;
struct dirent *d;
const char *name, *grp;
th_channel_t *ch;
dontwritesettings = 1;
th_channel_group_t *tcg;
TAILQ_INIT(&all_channel_groups);
TAILQ_INIT(&cl);
TAILQ_FOREACH(ce1, &settings_list, ce_link) {
if(ce1->ce_type != CFG_SUB || strcasecmp("channel-group", ce1->ce_key))
snprintf(buf, sizeof(buf), "%s/channel-group-settings.cfg", settings_dir);
config_read_file0(buf, &cl);
TAILQ_FOREACH(ce, &cl, ce_link) {
if(ce->ce_type != CFG_SUB || strcasecmp("channel-group", ce->ce_key))
continue;
if((name = config_get_str_sub(&ce1->ce_sub, "name", NULL)) == NULL)
if((name = config_get_str_sub(&ce->ce_sub, "name", NULL)) == NULL)
continue;
tcg = channel_group_find(name, 1);
TAILQ_FOREACH(ce2, &ce1->ce_sub, ce_link) {
if(ce2->ce_type != CFG_SUB || strcasecmp("channel", ce2->ce_key))
continue;
printf("Added channel group %s\n", name);
channel_group_find(name, 1);
}
config_free0(&cl);
if((name = config_get_str_sub(&ce2->ce_sub, "name", NULL)) == NULL)
continue;
snprintf(buf, sizeof(buf), "%s/channels", settings_dir);
ch = channel_find(name, 1, tcg);
if((dir = opendir(buf)) == NULL)
return;
while((d = readdir(dir)) != NULL) {
if(d->d_name[0] == '.')
continue;
snprintf(buf, sizeof(buf), "%s/channels/%s", settings_dir, d->d_name);
TAILQ_INIT(&cl);
config_read_file0(buf, &cl);
if((name = config_get_str_sub(&cl, "name", NULL)) == NULL)
continue;
if((grp = config_get_str_sub(&cl, "channel-group", NULL)) == NULL)
continue;
tcg = channel_group_find(grp, 1);
ch = channel_find(name, 1, tcg);
ch->ch_teletext_rundown =
atoi(config_get_str_sub(&ce2->ce_sub, "teletext-rundown", "0"));
}
ch->ch_teletext_rundown =
atoi(config_get_str_sub(&cl, "teletext-rundown", "0"));
config_free0(&cl);
}
tcg = channel_group_find("-disabled-", 1);
tcg->tcg_cant_delete_me = 1;
tcg->tcg_hidden = 1;
defgroup = channel_group_find("Uncategorized", 1);
defgroup->tcg_cant_delete_me = 1;
/* Static services */
TAILQ_FOREACH(ce, &config_list, ce_link) {
if(ce->ce_type == CFG_SUB && !strcasecmp("service", ce->ce_key)) {
service_load(&ce->ce_sub);
}
}
dontwritesettings = 0;
}
/**
* The index stuff should go away
*/
@ -347,7 +388,8 @@ channel_group_move_next(th_channel_group_t *tcg)
TAILQ_REMOVE(&all_channel_groups, tcg, tcg_global_link);
TAILQ_INSERT_AFTER(&all_channel_groups, n, tcg, tcg_global_link);
channel_settings_write();
channel_group_settings_write();
}
void
@ -360,57 +402,54 @@ channel_group_move_prev(th_channel_group_t *tcg)
TAILQ_REMOVE(&all_channel_groups, tcg, tcg_global_link);
TAILQ_INSERT_BEFORE(p, tcg, tcg_global_link);
channel_settings_write();
channel_group_settings_write();
}
/**
* Write out a config file with all channel groups
*
* We do this to maintain order of groups
*/
void
channel_settings_write(void)
static void
channel_group_settings_write(void)
{
FILE *fp;
th_channel_group_t *tcg;
th_channel_t *ch;
th_transport_t *t;
if(dontwritesettings || startupcounter > 0 || settingsfile == NULL)
return;
char buf[400];
snprintf(buf, sizeof(buf), "%s/channel-group-settings.cfg", settings_dir);
fp = fopen(settingsfile, "w+");
if(fp == NULL)
if((fp = settings_open_for_write(buf)) == NULL)
return;
TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link) {
fprintf(fp, "channel-group {\n"
"\tname = %s\n", tcg->tcg_name);
TAILQ_FOREACH(ch, &tcg->tcg_channels, ch_group_link) {
if(LIST_FIRST(&ch->ch_transports) == NULL)
continue;
fprintf(fp, "\tchannel {\n"
"\t\tname = %s\n", ch->ch_name);
if(ch->ch_teletext_rundown)
fprintf(fp, "\t\tteletext-rundown = %d\n", ch->ch_teletext_rundown);
fprintf(fp, "\t}\n");
}
fprintf(fp, "}\n");
}
LIST_FOREACH(t, &all_transports, tht_global_link) {
if(t->tht_channel == NULL)
continue;
fprintf(fp, "transport {\n"
"\tuniquename = %s\n"
"\tchannel = %s\n"
"\tprio = %d\n"
"}\n",
t->tht_uniquename,
t->tht_channel->ch_name,
t->tht_prio);
}
fclose(fp);
}
/**
* Write out a config file for a channel
*/
static void
channel_settings_write(th_channel_t *ch)
{
FILE *fp;
char buf[400];
snprintf(buf, sizeof(buf), "%s/channels/%s", settings_dir, ch->ch_sname);
if((fp = settings_open_for_write(buf)) == NULL)
return;
fprintf(fp, "name = %s\n", ch->ch_name);
fprintf(fp, "channel-group = %s\n", ch->ch_group->tcg_name);
if(ch->ch_teletext_rundown)
fprintf(fp, "teletext-rundown = %d\n", ch->ch_teletext_rundown);
fclose(fp);
}

View file

@ -44,8 +44,8 @@ void channel_group_move_prev(th_channel_group_t *tcg);
void channel_group_move_next(th_channel_group_t *tcg);
void channel_settings_write(void);
void channel_set_group(th_channel_t *ch, th_channel_group_t *tcg);
void channel_set_teletext_rundown(th_channel_t *ch, int v);
#endif /* CHANNELS_H */

48
dvb.c
View file

@ -23,7 +23,7 @@
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
@ -63,8 +63,10 @@ static void
dvb_add_adapter(const char *path)
{
char fname[256];
int fe;
th_dvb_adapter_t *tda;
int fe, i, r;
th_dvb_adapter_t *tda, *x;
char c;
char buf[400], *cp;
snprintf(fname, sizeof(fname), "%s/frontend0", path);
@ -103,11 +105,44 @@ dvb_add_adapter(const char *path)
pthread_cond_init(&tda->tda_cond, NULL);
TAILQ_INIT(&tda->tda_fe_cmd_queue);
LIST_INSERT_HEAD(&dvb_adapters_probing, tda, tda_link);
startupcounter++;
tda->tda_info = strdup(tda->tda_fe_info->name);
/*
* Generate a decent unique name for the adapter.
* If multiple adapters with the same name is found, we add
* a sequence number at the end
*/
for(i = 0; i < strlen(tda->tda_info); i++) {
c = tolower(tda->tda_info[i]);
if(isalnum(c))
buf[i] = c;
else
buf[i] = '_';
}
cp = &buf[i];
r = 0;
again:
if(r)
sprintf(cp, "-%d", r);
else
*cp = 0;
LIST_FOREACH(x, &dvb_adapters_probing, tda_link) {
if(!strcmp(buf, x->tda_sname)) {
r++;
goto again;
}
}
tda->tda_sname = strdup(buf);
LIST_INSERT_HEAD(&dvb_adapters_probing, tda, tda_link);
syslog(LOG_INFO, "Adding adapter %s (%s)", path, tda->tda_fe_info->name);
dtimer_arm(&tda->tda_fec_monitor_timer, dvb_fec_monitor, tda, 1);
@ -184,10 +219,13 @@ dvb_find_transport(th_dvb_mux_instance_t *tdmi, uint16_t tid,
t->tht_dvb_mux_instance = tdmi;
snprintf(tmp, sizeof(tmp), "%s/%04x", tdmi->tdmi_uniquename, sid);
free((void *)t->tht_uniquename);
t->tht_uniquename = strdup(tmp);
snprintf(tmp, sizeof(tmp), "%s/%04x", tdmi->tdmi_shortname, sid);
free((void *)t->tht_name);
t->tht_name = strdup(tmp);
LIST_INSERT_HEAD(&all_transports, t, tht_global_link);
dvb_table_add_transport(tdmi, t, pmt_pid);

View file

@ -81,7 +81,7 @@ dvb_add_mux(struct dvb_frontend_parameters *fe_param, fe_type_t type)
/* Generate names */
snprintf(buf, sizeof(buf), "%s/%s/%.1fMHz",
tda->tda_rootpath, typetxt,
tda->tda_sname, typetxt,
(float)fe_param->frequency / 1000000.0f);
tdmi->tdmi_uniquename = strdup(buf);

View file

@ -1510,7 +1510,7 @@ page_editchannel(http_connection_t *hc, const char *remain, void *opaque)
t->tht_scrambled ? "Yes" : "No",
t->tht_provider,
t->tht_network,
t->tht_uniquename);
t->tht_name);
}
@ -1562,7 +1562,7 @@ page_updatechannel(http_connection_t *hc, const char *remain, void *opaque)
}
if((s = http_arg_get(&hc->hc_url_args, "ttrp")) != NULL)
ch->ch_teletext_rundown = atoi(s);
channel_set_teletext_rundown(ch, atoi(s));
if((grp = http_arg_get(&hc->hc_url_args, "grp")) != NULL) {
tcg = channel_group_find(grp, 1);

34
main.c
View file

@ -61,6 +61,7 @@ int running;
int xmltvreload;
int startupcounter;
const char *tvheadend_streaming_host;
const char *settings_dir;
static pthread_mutex_t tag_mutex = PTHREAD_MUTEX_INITIALIZER;
static uint32_t tag_tally;
@ -114,6 +115,7 @@ main(int argc, char **argv)
int logfacility = LOG_DAEMON;
int disable_dvb = 0;
int p;
char buf[400];
signal(SIGPIPE, handle_sigpipe);
@ -168,7 +170,18 @@ main(int argc, char **argv)
openlog("tvheadend", LOG_PID, logfacility);
syslog(LOG_NOTICE, "Started HTS TV Headend");
settings_dir = config_get_str("settings-dir", "/tmp/tvheadend");
mkdir(settings_dir, 0777);
snprintf(buf, sizeof(buf), "%s/channels", settings_dir);
mkdir(buf, 0777);
snprintf(buf, sizeof(buf), "%s/transports", settings_dir);
mkdir(buf, 0777);
syslog(LOG_NOTICE, "Started HTS TV Headend, settings located in \"%s\"",
settings_dir);
dispatch_init();
@ -206,15 +219,14 @@ main(int argc, char **argv)
while(running) {
if(startupcounter == 0) {
channel_settings_write();
startupcounter = -1;
syslog(LOG_NOTICE,
"Initial input setup completed, starting output modules");
fprintf(stderr,
"Initial input setup completed, starting output modules\n");
startupcounter = -1;
pvr_init();
output_multicast_setup();
client_start();
@ -343,3 +355,17 @@ htstvstreamtype2txt(tv_streamtype_t s)
default: return "<unknown>";
}
}
FILE *
settings_open_for_write(const char *name)
{
FILE *fp;
fp = fopen(name, "w+");
if(fp == NULL)
syslog(LOG_ALERT, "Unable to open settings file \"%s\" -- %s",
name, strerror(errno));
return fp;
}

View file

@ -25,7 +25,7 @@
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
@ -57,6 +57,7 @@
static dtimer_t transport_monitor_timer;
static const char *transport_settings_path(th_transport_t *t);
void
@ -400,27 +401,22 @@ transport_set_channel(th_transport_t *t, th_channel_t *ch)
th_stream_t *st;
char *chname;
const char *n;
config_entry_t *ce;
char pid[30];
char lang[30];
struct config_head cl;
assert(t->tht_uniquename != NULL);
TAILQ_FOREACH(ce, &settings_list, ce_link) {
if(ce->ce_type != CFG_SUB || strcasecmp("transport", ce->ce_key))
continue;
n = transport_settings_path(t);
TAILQ_INIT(&cl);
config_read_file0(n, &cl);
n = config_get_str_sub(&ce->ce_sub, "uniquename", NULL);
if(n != NULL && !strcmp(n, t->tht_uniquename))
break;
}
t->tht_prio = atoi(config_get_str_sub(&cl, "prio", "0"));
n = config_get_str_sub(&cl, "channel", NULL);
if(n != NULL)
ch = channel_find(n, 1, NULL);
if(ce != NULL) {
t->tht_prio = atoi(config_get_str_sub(&ce->ce_sub, "prio", "0"));
n = config_get_str_sub(&ce->ce_sub, "channel", NULL);
if(n != NULL)
ch = channel_find(n, 1, NULL);
}
config_free0(&cl);
t->tht_channel = ch;
LIST_INSERT_SORTED(&ch->ch_transports, t, tht_channel_link, transportcmp);
@ -464,10 +460,13 @@ transport_set_priority(th_transport_t *t, int prio)
{
th_channel_t *ch = t->tht_channel;
if(t->tht_prio == prio)
return;
LIST_REMOVE(t, tht_channel_link);
t->tht_prio = prio;
LIST_INSERT_SORTED(&ch->ch_transports, t, tht_channel_link, transportcmp);
channel_settings_write();
transport_settings_write(t);
}
@ -480,5 +479,63 @@ transport_move(th_transport_t *t, th_channel_t *ch)
LIST_REMOVE(t, tht_channel_link);
t->tht_channel = ch;
LIST_INSERT_SORTED(&ch->ch_transports, t, tht_channel_link, transportcmp);
channel_settings_write();
transport_settings_write(t);
}
/**
* Generate a settings-dir relative path to transport config
*
* Must be free'd by caller
*/
static const char *
transport_settings_path(th_transport_t *t)
{
char buf[400];
char buf2[400];
int l, i;
char c;
l = strlen(t->tht_uniquename);
if(l >= sizeof(buf2))
l = sizeof(buf2) - 1;
for(i = 0; i < l; i++) {
c = tolower(t->tht_uniquename[i]);
if(isalnum(c))
buf2[i] = c;
else
buf2[i] = '_';
}
buf2[i] = 0;
snprintf(buf, sizeof(buf), "%s/transports/%s", settings_dir, buf2);
return strdup(buf);
}
/**
* Write out a config file for a channel
*/
void
transport_settings_write(th_transport_t *t)
{
FILE *fp;
const char *n;
n = transport_settings_path(t);
if((fp = settings_open_for_write(n)) != NULL) {
fprintf(fp,
"uniquename = %s\n"
"channel = %s\n"
"prio = %d\n",
t->tht_uniquename,
t->tht_channel->ch_name,
t->tht_prio);
fclose(fp);
}
free((void *)n);
}

View file

@ -40,4 +40,6 @@ void transport_set_priority(th_transport_t *t, int prio);
void transport_move(th_transport_t *t, th_channel_t *ch);
void transport_settings_write(th_transport_t *t);
#endif /* TRANSPORTS_H */

View file

@ -210,6 +210,7 @@ typedef struct th_dvb_adapter {
const char *tda_rootpath;
const char *tda_info;
const char *tda_sname;
LIST_ENTRY(th_dvb_adapter) tda_link;
@ -759,5 +760,8 @@ char *utf8tofilename(const char *in);
const char *htstvstreamtype2txt(tv_streamtype_t s);
uint32_t tag_get(void);
extern const char *tvheadend_streaming_host;
extern const char *settings_dir;
FILE *settings_open_for_write(const char *name);
FILE *settings_open_for_read(const char *name);
#endif /* TV_HEAD_H */