From eccc92a34d4809cd5926fa054ff7d231ae890c5e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2006 14:41:51 +0000 Subject: [PATCH] Fix infinite parse of recursive definitions Fixed the infinite parse (and eventually segfault) of recursive definitions. Also fixed the parse of a string slave PCM of direct plugins. --- include/local.h | 5 +++++ src/conf.c | 19 +++++++++++++++++++ src/pcm/pcm.c | 17 ++++++++++++----- src/pcm/pcm_adpcm.c | 2 +- src/pcm/pcm_alaw.c | 2 +- src/pcm/pcm_asym.c | 2 +- src/pcm/pcm_copy.c | 2 +- src/pcm/pcm_direct.c | 31 ++++++++++++++++++++++++++++++- src/pcm/pcm_direct.h | 2 +- src/pcm/pcm_dmix.c | 7 +++++-- src/pcm/pcm_dshare.c | 7 +++++-- src/pcm/pcm_dsnoop.c | 7 +++++-- src/pcm/pcm_extplug.c | 2 +- src/pcm/pcm_file.c | 2 +- src/pcm/pcm_hooks.c | 2 +- src/pcm/pcm_iec958.c | 2 +- src/pcm/pcm_ladspa.c | 2 +- src/pcm/pcm_lfloat.c | 2 +- src/pcm/pcm_linear.c | 2 +- src/pcm/pcm_local.h | 2 +- src/pcm/pcm_meter.c | 2 +- src/pcm/pcm_mulaw.c | 2 +- src/pcm/pcm_multi.c | 4 +++- src/pcm/pcm_plug.c | 2 +- src/pcm/pcm_rate.c | 2 +- src/pcm/pcm_route.c | 2 +- src/pcm/pcm_softvol.c | 2 +- src/rawmidi/rawmidi_virt.c | 7 ++++++- src/seq/seq.c | 21 ++++++++++++++++++--- 29 files changed, 127 insertions(+), 36 deletions(-) diff --git a/include/local.h b/include/local.h index bf53d512..b18d77a9 100644 --- a/include/local.h +++ b/include/local.h @@ -249,4 +249,9 @@ void *snd_dlobj_cache_lookup(const char *name); 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 diff --git a/src/conf.c b/src/conf.c index 78cc4cb3..3667ac06 100644 --- a/src/conf.c +++ b/src/conf.c @@ -440,6 +440,7 @@ struct _snd_config { } u; struct list_head list; snd_config_t *father; + int hop; }; struct filedesc { @@ -4011,6 +4012,24 @@ int snd_config_search_definition(snd_config_t *config, 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 */ diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index b3f3e6bd..6974aa0b 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -2098,7 +2098,8 @@ static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name, } 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; @@ -2107,6 +2108,7 @@ static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root, 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; @@ -2128,7 +2130,7 @@ int snd_pcm_open(snd_pcm_t **pcmp, const char *name, 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); } /** @@ -2145,7 +2147,7 @@ int snd_pcm_open_lconf(snd_pcm_t **pcmp, const char *name, 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 @@ -2187,11 +2189,16 @@ int snd_pcm_free(snd_pcm_t *pcm) 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 diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c index e5cb4506..8350dbec 100644 --- a/src/pcm/pcm_adpcm.c +++ b/src/pcm/pcm_adpcm.c @@ -666,7 +666,7 @@ int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_alaw.c b/src/pcm/pcm_alaw.c index 19045ec8..767e69fd 100644 --- a/src/pcm/pcm_alaw.c +++ b/src/pcm/pcm_alaw.c @@ -538,7 +538,7 @@ int _snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_asym.c b/src/pcm/pcm_asym.c index 5a2a4d64..660f3107 100644 --- a/src/pcm/pcm_asym.c +++ b/src/pcm/pcm_asym.c @@ -109,7 +109,7 @@ int _snd_pcm_asym_open(snd_pcm_t **pcmp, const char *name ATTRIBUTE_UNUSED, 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; } diff --git a/src/pcm/pcm_copy.c b/src/pcm/pcm_copy.c index 1e8510f4..b1525bfa 100644 --- a/src/pcm/pcm_copy.c +++ b/src/pcm/pcm_copy.c @@ -284,7 +284,7 @@ int _snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index 113930e1..ff4bddbf 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -1260,11 +1260,34 @@ int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg) /* * 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); @@ -1325,6 +1348,12 @@ int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction) 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) { diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h index 6a8bf791..31d3c4a9 100644 --- a/src/pcm/pcm_direct.h +++ b/src/pcm/pcm_direct.h @@ -186,7 +186,7 @@ int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix); 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); diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index 4f61a368..41a6bd8f 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -847,7 +847,10 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, 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; @@ -1124,7 +1127,7 @@ int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index c7cd9922..2d719dc9 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -672,7 +672,10 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, 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; @@ -873,7 +876,7 @@ int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c index 6fe1bd52..e2b91bbe 100644 --- a/src/pcm/pcm_dsnoop.c +++ b/src/pcm/pcm_dsnoop.c @@ -554,7 +554,10 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, 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; @@ -745,7 +748,7 @@ int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_extplug.c b/src/pcm/pcm_extplug.c index 36d4d248..2bde9e5b 100644 --- a/src/pcm/pcm_extplug.c +++ b/src/pcm/pcm_extplug.c @@ -622,7 +622,7 @@ int snd_pcm_extplug_create(snd_pcm_extplug_t *extplug, const char *name, 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; diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c index 4560bf4a..18951cc2 100644 --- a/src/pcm/pcm_file.c +++ b/src/pcm/pcm_file.c @@ -556,7 +556,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c index ce5f221c..f5136862 100644 --- a/src/pcm/pcm_hooks.c +++ b/src/pcm/pcm_hooks.c @@ -460,7 +460,7 @@ int _snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_iec958.c b/src/pcm/pcm_iec958.c index 3b120adc..79d611d1 100644 --- a/src/pcm/pcm_iec958.c +++ b/src/pcm/pcm_iec958.c @@ -662,7 +662,7 @@ int _snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_ladspa.c b/src/pcm/pcm_ladspa.c index 03f31f76..d4432ae3 100644 --- a/src/pcm/pcm_ladspa.c +++ b/src/pcm/pcm_ladspa.c @@ -1782,7 +1782,7 @@ int _snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_lfloat.c b/src/pcm/pcm_lfloat.c index d22277ba..7d946cbc 100644 --- a/src/pcm/pcm_lfloat.c +++ b/src/pcm/pcm_lfloat.c @@ -497,7 +497,7 @@ int _snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c index 43663787..6fc222cb 100644 --- a/src/pcm/pcm_linear.c +++ b/src/pcm/pcm_linear.c @@ -552,7 +552,7 @@ int _snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 24786392..e458b469 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -748,7 +748,7 @@ int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf, 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); diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c index 413b3cb4..b84747c4 100644 --- a/src/pcm/pcm_meter.c +++ b/src/pcm/pcm_meter.c @@ -779,7 +779,7 @@ int _snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_mulaw.c b/src/pcm/pcm_mulaw.c index 87b3235e..389326b6 100644 --- a/src/pcm/pcm_mulaw.c +++ b/src/pcm/pcm_mulaw.c @@ -553,7 +553,7 @@ int _snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index c2ade361..9c492f95 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -1103,7 +1103,9 @@ int _snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, } 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]); diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c index 0f5264c6..ad3e6507 100644 --- a/src/pcm/pcm_plug.c +++ b/src/pcm/pcm_plug.c @@ -1215,7 +1215,7 @@ int _snd_pcm_plug_open(snd_pcm_t **pcmp, const char *name, } #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; diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c index 28490ccc..f675a583 100644 --- a/src/pcm/pcm_rate.c +++ b/src/pcm/pcm_rate.c @@ -1532,7 +1532,7 @@ int _snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c index 09c1bd6f..daddf7c7 100644 --- a/src/pcm/pcm_route.c +++ b/src/pcm/pcm_route.c @@ -1152,7 +1152,7 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, 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); diff --git a/src/pcm/pcm_softvol.c b/src/pcm/pcm_softvol.c index 5c0413d8..d59d0315 100644 --- a/src/pcm/pcm_softvol.c +++ b/src/pcm/pcm_softvol.c @@ -814,7 +814,7 @@ int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/rawmidi/rawmidi_virt.c b/src/rawmidi/rawmidi_virt.c index 99c4be22..2cee7b34 100644 --- a/src/rawmidi/rawmidi_virt.c +++ b/src/rawmidi/rawmidi_virt.c @@ -53,6 +53,10 @@ typedef struct { 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) @@ -439,7 +443,8 @@ int _snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, 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; diff --git a/src/seq/seq.c b/src/seq/seq.c index 2ae83a7a..df7b64e6 100644 --- a/src/seq/seq.c +++ b/src/seq/seq.c @@ -919,7 +919,8 @@ static int snd_seq_open_conf(snd_seq_t **seqp, const char *name, } 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; @@ -928,6 +929,7 @@ static int snd_seq_open_noupdate(snd_seq_t **seqp, snd_config_t *root, 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; @@ -971,7 +973,7 @@ int snd_seq_open(snd_seq_t **seqp, const char *name, 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); } /** @@ -993,9 +995,22 @@ int snd_seq_open_lconf(snd_seq_t **seqp, const char *name, 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() -- 2.47.1