mixer: Fix default_unit switching with mixers that have no devices

Apparently it's possible for a mixer to have no devices:

$ mixer -f /dev/mixer2
pcm2:mixer: <USB audio> at ? kld snd_uaudio (rec)
$

If this is the default sound device, an attempt to change the default
unit using mixer -d fails with a segfault because mod_dunit is called
with a NULL device pointer, which is dereferenced to get the parent
mixer.

ctl_dunit seems to be a dummy, i.e., we don't actually need it and can
simply pass the mixer to mod_dunit() directly.  This patch removes that
structure and associated indirection to fix the crash.

Reviewed by:	christos, hselasky
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D38060
This commit is contained in:
Mark Johnston 2023-01-16 08:02:54 -05:00
parent 228c632ab3
commit 5c2b216a1c

View file

@ -42,8 +42,8 @@ static void printall(struct mixer *, int);
static void printminfo(struct mixer *, int);
static void printdev(struct mixer *, int);
static void printrecsrc(struct mixer *, int); /* XXX: change name */
static int set_dunit(struct mixer *, int);
/* Control handlers */
static int mod_dunit(struct mix_dev *, void *);
static int mod_volume(struct mix_dev *, void *);
static int mod_mute(struct mix_dev *, void *);
static int mod_recsrc(struct mix_dev *, void *);
@ -51,14 +51,6 @@ static int print_volume(struct mix_dev *, void *);
static int print_mute(struct mix_dev *, void *);
static int print_recsrc(struct mix_dev *, void *);
static const mix_ctl_t ctl_dunit = {
.parent_dev = NULL,
.id = -1,
.name = "default_unit",
.mod = mod_dunit,
.print = NULL
};
int
main(int argc, char *argv[])
{
@ -125,7 +117,7 @@ main(int argc, char *argv[])
initctls(m);
if (dflag && ctl_dunit.mod(m->dev, &dunit) < 0)
if (dflag && set_dunit(m, dunit) < 0)
goto parse;
if (sflag) {
printrecsrc(m, oflag);
@ -316,20 +308,19 @@ printrecsrc(struct mixer *m, int oflag)
}
static int
mod_dunit(struct mix_dev *d, void *p)
set_dunit(struct mixer *m, int dunit)
{
int dunit = *((int *)p);
int n;
if ((n = mixer_get_dunit()) < 0) {
warn("cannot get default unit");
return (-1);
}
if (mixer_set_dunit(d->parent_mixer, dunit) < 0) {
if (mixer_set_dunit(m, dunit) < 0) {
warn("cannot set default unit to: %d", dunit);
return (-1);
}
printf("%s: %d -> %d\n", ctl_dunit.name, n, dunit);
printf("default_unit: %d -> %d\n", n, dunit);
return (0);
}