From 6177fec24cad29ccf310c2e46674df8bbd5fa3a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Mon, 28 Jan 2008 20:40:35 +0000 Subject: [PATCH] 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) --- channels.c | 161 ++++++++++++++++++++++++++++++------------------ channels.h | 4 +- dvb.c | 48 +++++++++++++-- dvb_muxconfig.c | 2 +- htmlui.c | 4 +- main.c | 34 ++++++++-- transports.c | 91 ++++++++++++++++++++++----- transports.h | 2 + tvhead.h | 4 ++ 9 files changed, 258 insertions(+), 92 deletions(-) diff --git a/channels.c b/channels.c index 1aae6760..68d0be84 100644 --- a/channels.c +++ b/channels.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -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); +} + diff --git a/channels.h b/channels.h index fbb1b77d..d4414c4d 100644 --- a/channels.h +++ b/channels.h @@ -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 */ diff --git a/dvb.c b/dvb.c index 19f0bfa9..9139bed2 100644 --- a/dvb.c +++ b/dvb.c @@ -23,7 +23,7 @@ #include #include #include - +#include #include #include #include @@ -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); diff --git a/dvb_muxconfig.c b/dvb_muxconfig.c index 5193e773..cc940fdb 100644 --- a/dvb_muxconfig.c +++ b/dvb_muxconfig.c @@ -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); diff --git a/htmlui.c b/htmlui.c index 203f43a2..2a1c3a50 100644 --- a/htmlui.c +++ b/htmlui.c @@ -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); diff --git a/main.c b/main.c index 5ad59f04..303bd03a 100644 --- a/main.c +++ b/main.c @@ -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 ""; } } + + +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; +} + diff --git a/transports.c b/transports.c index 7058f1ed..d26075e2 100644 --- a/transports.c +++ b/transports.c @@ -25,7 +25,7 @@ #include #include #include - +#include #include #include #include @@ -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); +} + diff --git a/transports.h b/transports.h index ae5c5ecd..095a0390 100644 --- a/transports.h +++ b/transports.h @@ -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 */ diff --git a/tvhead.h b/tvhead.h index b0de4bbf..ef9c3eff 100644 --- a/tvhead.h +++ b/tvhead.h @@ -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 */