mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-12-16 08:56:42 -05:00
Added snd_config_update_r, snd_config_update_free functions
This commit is contained in:
parent
cd8b1b3c11
commit
76c8029e2b
2 changed files with 139 additions and 60 deletions
|
|
@ -61,6 +61,8 @@ typedef enum _snd_config_type {
|
||||||
typedef struct _snd_config snd_config_t;
|
typedef struct _snd_config snd_config_t;
|
||||||
/** Config compound iterator */
|
/** Config compound iterator */
|
||||||
typedef struct _snd_config_iterator *snd_config_iterator_t;
|
typedef struct _snd_config_iterator *snd_config_iterator_t;
|
||||||
|
/** Config private update structure */
|
||||||
|
typedef struct _snd_config_update snd_config_update_t;
|
||||||
|
|
||||||
extern snd_config_t *snd_config;
|
extern snd_config_t *snd_config;
|
||||||
|
|
||||||
|
|
@ -69,6 +71,8 @@ int snd_config_top(snd_config_t **config);
|
||||||
int snd_config_load(snd_config_t *config, snd_input_t *in);
|
int snd_config_load(snd_config_t *config, snd_input_t *in);
|
||||||
int snd_config_save(snd_config_t *config, snd_output_t *out);
|
int snd_config_save(snd_config_t *config, snd_output_t *out);
|
||||||
int snd_config_update(void);
|
int snd_config_update(void);
|
||||||
|
int snd_config_update_r(snd_config_t **top, snd_config_update_t **update, const char *path);
|
||||||
|
int snd_config_update_free(snd_config_update_t *update);
|
||||||
|
|
||||||
int snd_config_search(snd_config_t *config, const char *key,
|
int snd_config_search(snd_config_t *config, const char *key,
|
||||||
snd_config_t **result);
|
snd_config_t **result);
|
||||||
|
|
|
||||||
195
src/conf.c
195
src/conf.c
|
|
@ -338,6 +338,7 @@ func.remove_first_char {
|
||||||
#include <wordexp.h>
|
#include <wordexp.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <pthread.h>
|
||||||
#include "local.h"
|
#include "local.h"
|
||||||
|
|
||||||
#ifndef DOC_HIDDEN
|
#ifndef DOC_HIDDEN
|
||||||
|
|
@ -2205,17 +2206,22 @@ int snd_config_search_alias_hooks(snd_config_t *config,
|
||||||
#define ALSA_CONFIG_PATH_DEFAULT DATADIR "/alsa/alsa.conf"
|
#define ALSA_CONFIG_PATH_DEFAULT DATADIR "/alsa/alsa.conf"
|
||||||
|
|
||||||
/** \ingroup Config
|
/** \ingroup Config
|
||||||
* Config top node */
|
* Config top node (global configuration) */
|
||||||
snd_config_t *snd_config = NULL;
|
snd_config_t *snd_config = NULL;
|
||||||
|
|
||||||
static struct finfo {
|
struct finfo {
|
||||||
char *name;
|
char *name;
|
||||||
dev_t dev;
|
dev_t dev;
|
||||||
ino_t ino;
|
ino_t ino;
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
} *files_info = NULL;
|
};
|
||||||
|
|
||||||
static unsigned int files_info_count = 0;
|
struct _snd_config_update {
|
||||||
|
unsigned int count;
|
||||||
|
struct finfo *finfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
static snd_config_update_t *snd_config_global_update = NULL;
|
||||||
|
|
||||||
static int snd_config_hooks_call(snd_config_t *root, snd_config_t *config, snd_config_t *private_data)
|
static int snd_config_hooks_call(snd_config_t *root, snd_config_t *config, snd_config_t *private_data)
|
||||||
{
|
{
|
||||||
|
|
@ -2536,29 +2542,40 @@ SND_DLSYM_BUILD_VERSION(snd_config_hook_load_for_all_cards, SND_CONFIG_DLSYM_VER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Update #snd_config rereading (if needed) global configuration files.
|
* \brief Update #snd_config rereading (if needed) configuration files.
|
||||||
|
* \param top Top node
|
||||||
|
* \param update Private update information
|
||||||
|
* \param cfgs Configuration files in list delimited with ':', if NULL -> default global
|
||||||
|
* configuration file is used - "/usr/share/alsa/alsa.conf".
|
||||||
* \return non-negative value on success, otherwise a negative error code
|
* \return non-negative value on success, otherwise a negative error code
|
||||||
* \retval 0 no action is needed
|
* \retval 0 no action is needed
|
||||||
* \retval 1 tree has been rebuild
|
* \retval 1 tree has been rebuild
|
||||||
*
|
*
|
||||||
* The global configuration files are specified in environment variable ALSA_CONFIG_PATH.
|
* The global configuration files are specified in environment variable ALSA_CONFIG_PATH.
|
||||||
* If it is not set the default value is "/usr/share/alsa/alsa.conf".
|
|
||||||
*
|
*
|
||||||
* Warning: If config tree is reread all the string pointer and config
|
* Warning: If config tree is reread all the string pointer and config
|
||||||
* node handle previously obtained from this tree become invalid
|
* node handle previously obtained from this tree become invalid.
|
||||||
*/
|
*/
|
||||||
int snd_config_update()
|
int snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, const char *cfgs)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
char *configs, *c;
|
const char *configs, *c;
|
||||||
unsigned int k;
|
unsigned int k;
|
||||||
wordexp_t we;
|
wordexp_t we;
|
||||||
size_t l;
|
size_t l;
|
||||||
struct finfo *fi = NULL;
|
snd_config_update_t *local;
|
||||||
unsigned int fi_count;
|
snd_config_update_t *update;
|
||||||
configs = getenv(ALSA_CONFIG_PATH_VAR);
|
snd_config_t *top;
|
||||||
if (!configs)
|
|
||||||
configs = ALSA_CONFIG_PATH_DEFAULT;
|
assert(_top && _update);
|
||||||
|
top = *_top;
|
||||||
|
update = *_update;
|
||||||
|
configs = cfgs;
|
||||||
|
if (!configs) {
|
||||||
|
configs = getenv(ALSA_CONFIG_PATH_VAR);
|
||||||
|
if (!configs)
|
||||||
|
configs = ALSA_CONFIG_PATH_DEFAULT;
|
||||||
|
}
|
||||||
for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) {
|
for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) {
|
||||||
c += l;
|
c += l;
|
||||||
k++;
|
k++;
|
||||||
|
|
@ -2566,12 +2583,19 @@ int snd_config_update()
|
||||||
break;
|
break;
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
fi_count = k;
|
if (k == 0) {
|
||||||
if (fi_count == 0)
|
local = NULL;
|
||||||
goto _reread;
|
goto _reread;
|
||||||
fi = calloc(fi_count, sizeof(*fi));
|
}
|
||||||
if (!fi)
|
local = (snd_config_update_t *)calloc(1, sizeof(snd_config_update_t));
|
||||||
|
if (!local)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
local->count = k;
|
||||||
|
local->finfo = calloc(local->count, sizeof(struct finfo));
|
||||||
|
if (!local->finfo) {
|
||||||
|
free(local);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) {
|
for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) {
|
||||||
char name[l + 1];
|
char name[l + 1];
|
||||||
memcpy(name, c, l);
|
memcpy(name, c, l);
|
||||||
|
|
@ -2589,9 +2613,9 @@ int snd_config_update()
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto _end;
|
goto _end;
|
||||||
}
|
}
|
||||||
fi[k].name = strdup(we.we_wordv[0]);
|
local->finfo[k].name = strdup(we.we_wordv[0]);
|
||||||
wordfree(&we);
|
wordfree(&we);
|
||||||
if (!fi[k].name) {
|
if (!local->finfo[k].name) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto _end;
|
goto _end;
|
||||||
}
|
}
|
||||||
|
|
@ -2601,81 +2625,132 @@ int snd_config_update()
|
||||||
break;
|
break;
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
for (k = 0; k < fi_count; ++k) {
|
for (k = 0; k < local->count; ++k) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(fi[k].name, &st) >= 0) {
|
struct finfo *lf = &local->finfo[k];
|
||||||
fi[k].dev = st.st_dev;
|
if (stat(lf->name, &st) >= 0) {
|
||||||
fi[k].ino = st.st_ino;
|
lf->dev = st.st_dev;
|
||||||
fi[k].mtime = st.st_mtime;
|
lf->ino = st.st_ino;
|
||||||
|
lf->mtime = st.st_mtime;
|
||||||
} else {
|
} else {
|
||||||
memmove(&fi[k], &fi[k+1], sizeof(*fi) * (fi_count - k - 1));
|
memmove(&local->finfo[k], &local->finfo[k+1], sizeof(struct finfo) * (local->count - k - 1));
|
||||||
k--;
|
k--;
|
||||||
fi_count--;
|
local->count--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!files_info)
|
if (!update)
|
||||||
goto _reread;
|
goto _reread;
|
||||||
if (fi_count != files_info_count)
|
if (local->count != update->count)
|
||||||
goto _reread;
|
goto _reread;
|
||||||
for (k = 0; k < fi_count; ++k) {
|
for (k = 0; k < local->count; ++k) {
|
||||||
if (strcmp(fi[k].name, files_info[k].name) != 0 ||
|
struct finfo *lf = &local->finfo[k];
|
||||||
fi[k].dev != files_info[k].dev ||
|
struct finfo *uf = &update->finfo[k];
|
||||||
fi[k].ino != files_info[k].ino ||
|
if (strcmp(lf->name, uf->name) != 0 ||
|
||||||
fi[k].mtime != files_info[k].mtime)
|
lf->dev != uf->dev ||
|
||||||
|
lf->ino != uf->ino ||
|
||||||
|
lf->mtime != uf->mtime)
|
||||||
goto _reread;
|
goto _reread;
|
||||||
}
|
}
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
_end:
|
_end:
|
||||||
if (err < 0 && snd_config) {
|
if (err < 0) {
|
||||||
snd_config_delete(snd_config);
|
if (top) {
|
||||||
snd_config = NULL;
|
snd_config_delete(top);
|
||||||
|
*_top = NULL;
|
||||||
|
}
|
||||||
|
if (update) {
|
||||||
|
snd_config_update_free(update);
|
||||||
|
*_update = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (k = 0; k < fi_count; ++k)
|
if (local)
|
||||||
free(fi[k].name);
|
snd_config_update_free(local);
|
||||||
if (fi)
|
|
||||||
free(fi);
|
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
_reread:
|
_reread:
|
||||||
if (files_info) {
|
*_top = NULL;
|
||||||
for (k = 0; k < files_info_count; ++k)
|
*_update = NULL;
|
||||||
free(files_info[k].name);
|
if (update) {
|
||||||
free(files_info);
|
snd_config_update_free(update);
|
||||||
files_info = NULL;
|
update = NULL;
|
||||||
files_info_count = 0;
|
}
|
||||||
|
if (top) {
|
||||||
|
snd_config_delete(top);
|
||||||
|
top = NULL;
|
||||||
}
|
}
|
||||||
if (snd_config) {
|
err = snd_config_top(&top);
|
||||||
snd_config_delete(snd_config);
|
|
||||||
snd_config = NULL;
|
|
||||||
}
|
|
||||||
err = snd_config_top(&snd_config);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto _end;
|
goto _end;
|
||||||
for (k = 0; k < fi_count; ++k) {
|
if (!local)
|
||||||
|
goto _skip;
|
||||||
|
for (k = 0; k < local->count; ++k) {
|
||||||
snd_input_t *in;
|
snd_input_t *in;
|
||||||
err = snd_input_stdio_open(&in, fi[k].name, "r");
|
err = snd_input_stdio_open(&in, local->finfo[k].name, "r");
|
||||||
if (err >= 0) {
|
if (err >= 0) {
|
||||||
err = snd_config_load(snd_config, in);
|
err = snd_config_load(top, in);
|
||||||
snd_input_close(in);
|
snd_input_close(in);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[k].name);
|
SNDERR("%s may be old or corrupted: consider to remove or fix it", local->finfo[k].name);
|
||||||
goto _end;
|
goto _end;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SNDERR("cannot access file %s", fi[k].name);
|
SNDERR("cannot access file %s", local->finfo[k].name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = snd_config_hooks(snd_config, NULL);
|
_skip:
|
||||||
|
err = snd_config_hooks(top, NULL);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
SNDERR("hooks failed, removing configuration");
|
SNDERR("hooks failed, removing configuration");
|
||||||
goto _end;
|
goto _end;
|
||||||
}
|
}
|
||||||
files_info = fi;
|
*_top = top;
|
||||||
files_info_count = fi_count;
|
*_update = local;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static pthread_mutex_t snd_config_update_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Update #snd_config rereading (if needed) global configuration files.
|
||||||
|
* \return non-negative value on success, otherwise a negative error code
|
||||||
|
* \retval 0 no action is needed
|
||||||
|
* \retval 1 tree has been rebuild
|
||||||
|
*
|
||||||
|
* The global configuration files are specified in environment variable ALSA_CONFIG_PATH.
|
||||||
|
* If it is not set the default value is "/usr/share/alsa/alsa.conf".
|
||||||
|
*
|
||||||
|
* Warning: If config tree is reread all the string pointer and config
|
||||||
|
* node handle previously obtained from this tree become invalid.
|
||||||
|
*/
|
||||||
|
int snd_config_update(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&snd_config_update_mutex);
|
||||||
|
err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL);
|
||||||
|
pthread_mutex_unlock(&snd_config_update_mutex);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Free private update structure
|
||||||
|
* \param update private update structure to free
|
||||||
|
* \return non-negative value on success, otherwise a negative error code
|
||||||
|
*/
|
||||||
|
int snd_config_update_free(snd_config_update_t *update)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
|
||||||
|
assert(update);
|
||||||
|
assert(update->count > 0 && update->finfo);
|
||||||
|
for (k = 0; k < update->count; k++)
|
||||||
|
free(update->finfo[k].name);
|
||||||
|
if (update->finfo)
|
||||||
|
free(update->finfo);
|
||||||
|
free(update);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return an iterator pointing to first leaf of a compound config node
|
* \brief Return an iterator pointing to first leaf of a compound config node
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue