git: 5c2b216a1cd8 - main - mixer: Fix default_unit switching with mixers that have no devices

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 16 Jan 2023 13:05:08 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=5c2b216a1cd8de3aabfa9e76ca8f38774acd591e

commit 5c2b216a1cd8de3aabfa9e76ca8f38774acd591e
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2023-01-16 13:02:54 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2023-01-16 13:02:54 +0000

    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
---
 usr.sbin/mixer/mixer.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/usr.sbin/mixer/mixer.c b/usr.sbin/mixer/mixer.c
index e216efe3313c..6095f7550ea8 100644
--- a/usr.sbin/mixer/mixer.c
+++ b/usr.sbin/mixer/mixer.c
@@ -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);
 }