Fixed the infinite parse (and eventually segfault) of recursive definitions.
Also fixed the parse of a string slave PCM of direct plugins.
int snd_dlobj_cache_add(const char *name, void *dlobj, void *open_func);
void snd_dlobj_cache_cleanup(void);
+/* for recursive checks */
+void snd_config_set_hop(snd_config_t *conf, int hop);
+int snd_config_check_hop(snd_config_t *conf);
+#define SND_CONF_MAX_HOPS 64
+
#endif
} u;
struct list_head list;
snd_config_t *father;
+ int hop;
};
struct filedesc {
return snd_config_expand(conf, config, args, NULL, result);
}
+#ifndef DOC_HIDDEN
+void snd_config_set_hop(snd_config_t *conf, int hop)
+{
+ conf->hop = hop;
+}
+
+int snd_config_check_hop(snd_config_t *conf)
+{
+ if (conf) {
+ if (conf->hop >= SND_CONF_MAX_HOPS) {
+ SYSERR("Too many definition levels (looped?)\n");
+ return -EINVAL;
+ }
+ return conf->hop;
+ }
+ return 0;
+}
+#endif
#if 0
/* Not strictly needed, but useful to check for memory leaks */
}
static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root,
- const char *name, snd_pcm_stream_t stream, int mode)
+ const char *name, snd_pcm_stream_t stream,
+ int mode, int hop)
{
int err;
snd_config_t *pcm_conf;
SNDERR("Unknown PCM %s", name);
return err;
}
+ snd_config_set_hop(pcm_conf, hop);
err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode);
snd_config_delete(pcm_conf);
return err;
err = snd_config_update();
if (err < 0)
return err;
- return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode);
+ return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode, 0);
}
/**
snd_config_t *lconf)
{
assert(pcmp && name && lconf);
- return snd_pcm_open_noupdate(pcmp, lconf, name, stream, mode);
+ return snd_pcm_open_noupdate(pcmp, lconf, name, stream, mode, 0);
}
#ifndef DOC_HIDDEN
int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
snd_config_t *conf, snd_pcm_stream_t stream,
- int mode)
+ int mode, snd_config_t *parent_conf)
{
const char *str;
+ int hop;
+
+ if ((hop = snd_config_check_hop(parent_conf)) < 0)
+ return hop;
if (snd_config_get_string(conf, &str) >= 0)
- return snd_pcm_open_noupdate(pcmp, root, str, stream, mode);
+ return snd_pcm_open_noupdate(pcmp, root, str, stream, mode,
+ hop + 1);
return snd_pcm_open_conf(pcmp, NULL, root, conf, stream, mode);
}
#endif
SNDERR("invalid slave format");
return -EINVAL;
}
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
SNDERR("invalid slave format");
return -EINVAL;
}
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0)
return err;
- err = snd_pcm_open_slave(pcmp, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(pcmp, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
return err;
}
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0)
return err;
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
/*
* parse slave config and calculate the ipc_key offset
*/
-int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction)
+
+static int _snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root,
+ snd_config_t *sconf,
+ int direction,
+ int hop)
{
snd_config_iterator_t i, next;
int err;
long card = 0, device = 0, subdevice = 0;
+ const char *str;
+
+ if (snd_config_get_string(sconf, &str) >= 0) {
+ snd_config_t *pcm_conf;
+ if (hop > SND_CONF_MAX_HOPS) {
+ SNDERR("Too many definition levels (looped?)");
+ return -EINVAL;
+ }
+ err = snd_config_search_definition(root, "pcm", str, &pcm_conf);
+ if (err < 0) {
+ SNDERR("Unknown slave PCM %s", str);
+ return err;
+ }
+ err = _snd_pcm_direct_get_slave_ipc_offset(root, pcm_conf,
+ direction,
+ hop + 1);
+ snd_config_delete(pcm_conf);
+ return err;
+ }
snd_config_for_each(i, next, sconf) {
snd_config_t *n = snd_config_iterator_entry(i);
return direction + (card << 1) + (device << 4) + (subdevice << 8);
}
+int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root,
+ snd_config_t *sconf,
+ int direction)
+{
+ return _snd_pcm_direct_get_slave_ipc_offset(root, sconf, direction, 0);
+}
int snd_pcm_direct_parse_open_conf(snd_config_t *conf, struct snd_pcm_direct_open_conf *rec)
{
void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix);
int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name);
-int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction);
+int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root, snd_config_t *sconf, int direction);
int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
if (first_instance) {
- ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode | SND_PCM_NONBLOCK);
+ /* recursion is already checked in
+ snd_pcm_direct_get_slave_ipc_offset() */
+ ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
+ mode | SND_PCM_NONBLOCK, NULL);
if (ret < 0) {
SNDERR("unable to open slave");
goto _err;
params.period_size = psize;
params.buffer_size = bsize;
- ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream);
+ ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream);
if (ipc_offset < 0) {
snd_config_delete(sconf);
return ipc_offset;
dshare->sync_ptr = snd_pcm_dshare_sync_ptr;
if (first_instance) {
- ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode | SND_PCM_NONBLOCK);
+ /* recursion is already checked in
+ snd_pcm_direct_get_slave_ipc_offset() */
+ ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
+ mode | SND_PCM_NONBLOCK, NULL);
if (ret < 0) {
SNDERR("unable to open slave");
goto _err;
params.period_size = psize;
params.buffer_size = bsize;
- ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream);
+ ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream);
if (ipc_offset < 0) {
snd_config_delete(sconf);
return ipc_offset;
dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
if (first_instance) {
- ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode | SND_PCM_NONBLOCK);
+ /* recursion is already checked in
+ snd_pcm_direct_get_slave_ipc_offset() */
+ ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
+ mode | SND_PCM_NONBLOCK, NULL);
if (ret < 0) {
SNDERR("unable to open slave");
goto _err;
params.period_size = psize;
params.buffer_size = bsize;
- ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream);
+ ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream);
if (ipc_offset < 0) {
snd_config_delete(sconf);
return ipc_offset;
err = snd_pcm_slave_conf(root, slave_conf, &sconf, 0);
if (err < 0)
return err;
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, NULL);
snd_config_delete(sconf);
if (err < 0)
return err;
SNDERR("file is not defined");
return -EINVAL;
}
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0)
return err;
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
SNDERR("invalid slave format");
return -EINVAL;
}
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0)
return err;
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
SNDERR("slave format is not linear integer or linear float");
return -EINVAL;
}
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
SNDERR("slave format is not linear");
return -EINVAL;
}
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
snd_config_t *conf, snd_pcm_stream_t stream,
- int mode);
+ int mode, snd_config_t *parent_conf);
int snd_pcm_conf_generic_id(const char *id);
int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, int mmap_emulation, int sync_ptr_ioctl);
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0)
return err;
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
SNDERR("invalid slave format");
return -EINVAL;
}
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
}
for (idx = 0; idx < slaves_count; ++idx) {
- err = snd_pcm_open_slave(&slaves_pcm[idx], root, slaves_conf[idx], stream, mode);
+ err = snd_pcm_open_slave(&slaves_pcm[idx], root,
+ slaves_conf[idx], stream, mode,
+ conf);
if (err < 0)
goto _free;
snd_config_delete(slaves_conf[idx]);
}
#endif
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
SNDERR("slave format is not linear");
return -EINVAL;
}
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
return err;
}
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0) {
free(ttable);
snd_config_delete(sconf);
return -EINVAL;
}
- err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;
snd_seq_event_t out_event;
int pending;
} snd_rawmidi_virtual_t;
+
+int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name,
+ int streams, int mode, snd_config_t *lconf,
+ snd_config_t *parent_conf);
#endif
static int snd_rawmidi_virtual_close(snd_rawmidi_t *rmidi)
if (! slave_str)
slave_str = "default";
- err = snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode, root);
+ err = _snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode,
+ root, conf);
if (err < 0)
return err;
}
static int snd_seq_open_noupdate(snd_seq_t **seqp, snd_config_t *root,
- const char *name, int streams, int mode)
+ const char *name, int streams, int mode,
+ int hop)
{
int err;
snd_config_t *seq_conf;
SNDERR("Unknown SEQ %s", name);
return err;
}
+ snd_config_set_hop(seq_conf, hop);
err = snd_seq_open_conf(seqp, name, root, seq_conf, streams, mode);
snd_config_delete(seq_conf);
return err;
err = snd_config_update();
if (err < 0)
return err;
- return snd_seq_open_noupdate(seqp, snd_config, name, streams, mode);
+ return snd_seq_open_noupdate(seqp, snd_config, name, streams, mode, 0);
}
/**
int streams, int mode, snd_config_t *lconf)
{
assert(seqp && name && lconf);
- return snd_seq_open_noupdate(seqp, lconf, name, streams, mode);
+ return snd_seq_open_noupdate(seqp, lconf, name, streams, mode, 0);
}
+#ifndef DOC_HIDDEN
+int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name,
+ int streams, int mode, snd_config_t *lconf,
+ snd_config_t *parent_conf)
+{
+ int hop;
+ assert(seqp && name && lconf);
+ if ((hop = snd_config_check_hop(parent_conf)) < 0)
+ return hop;
+ return snd_seq_open_noupdate(seqp, lconf, name, streams, mode, hop + 1);
+}
+#endif
+
/**
* \brief Close the sequencer
* \param seq Handle returned from #snd_seq_open()