libc/citrus: Catch a NULL pointer earlier, check for empty string later.
[dragonfly.git] / usr.sbin / mixer / mixer.c
blobe14543dfe8a8371be206a0e0bbfa47c07aa1ed69
1 /*
2 * This is an example of a mixer program for Linux
4 * updated 1/1/93 to add stereo, level query, broken
5 * devmask kludge - cmetz@thor.tjhsst.edu
7 * (C) Craig Metz and Hannu Savolainen 1993.
9 * You may do anything you wish with this program.
11 * ditto for my modifications (John-Mark Gurney, 1997)
13 * $FreeBSD: head/usr.sbin/mixer/mixer.c 230611 2012-01-27 09:15:55Z mav $
16 #include <err.h>
17 #include <fcntl.h>
18 #include <libgen.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <sys/soundcard.h>
26 static const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
28 static void usage(int devmask, int recmask);
29 static int res_name(const char *name, int mask);
30 static void print_recsrc(int recsrc, int recmask, int sflag);
32 static void
33 usage(int devmask, int recmask)
35 int i, n;
37 printf("usage: mixer [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n"
38 " mixer [-f device] [-s | -S] recsrc ...\n"
39 " mixer [-f device] [-s | -S] {^|+|-|=}rec rdev ...\n");
40 if (devmask != 0) {
41 printf(" devices: ");
42 for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
43 if ((1 << i) & devmask) {
44 if (n)
45 printf(", ");
46 printf("%s", names[i]);
47 n++;
51 if (recmask != 0) {
52 printf("\n rec devices: ");
53 for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
54 if ((1 << i) & recmask) {
55 if (n)
56 printf(", ");
57 printf("%s", names[i]);
58 n++;
62 printf("\n");
63 exit(1);
66 static int
67 res_name(const char *name, int mask)
69 int i;
71 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
72 if ((1 << i) & mask && strcmp(names[i], name) == 0)
73 break;
75 if (i == SOUND_MIXER_NRDEVICES)
76 return (-1);
78 return (i);
81 static void
82 print_recsrc(int recsrc, int recmask, int sflag)
84 int i, n;
86 if (recmask == 0)
87 return;
89 if (!sflag)
90 printf("Recording source: ");
92 for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
93 if ((1 << i) & recsrc) {
94 if (sflag)
95 printf("%srec ", n ? " +" : "=");
96 else if (n)
97 printf(", ");
98 printf("%s", names[i]);
99 n++;
102 if (!sflag)
103 printf("\n");
107 main(int argc, char *argv[])
109 char mixer[PATH_MAX] = "/dev/mixer";
110 char lstr[8], rstr[8];
111 char *name, *eptr;
112 int devmask = 0, recmask = 0, recsrc = 0, orecsrc;
113 int dusage = 0, drecsrc = 0, sflag = 0, Sflag = 0;
114 int l, r, lrel, rrel;
115 int ch, i, bar, baz, dev, m, n, t;
117 if ((name = strdup(basename(argv[0]))) == NULL)
118 err(1, "strdup()");
119 if (strncmp(name, "mixer", 5) == 0 && name[5] != '\0') {
120 n = strtol(name + 5, &eptr, 10) - 1;
121 if (n > 0 && *eptr == '\0')
122 snprintf(mixer, PATH_MAX - 1, "/dev/mixer%d", n);
124 free(name);
125 name = mixer;
127 n = 1;
128 for (;;) {
129 if (n >= argc || *argv[n] != '-')
130 break;
131 if (strlen(argv[n]) != 2) {
132 if (strcmp(argv[n] + 1, "rec") != 0)
133 dusage = 1;
134 break;
136 ch = *(argv[n] + 1);
137 if (ch == 'f' && n < argc - 1) {
138 name = argv[n + 1];
139 n += 2;
140 } else if (ch == 's') {
141 sflag = 1;
142 n++;
143 } else if (ch == 'S') {
144 Sflag = 1;
145 n++;
146 } else {
147 dusage = 1;
148 break;
151 if (sflag && Sflag)
152 dusage = 1;
154 argc -= n - 1;
155 argv += n - 1;
157 if ((baz = open(name, O_RDWR)) < 0)
158 err(1, "%s", name);
159 if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
160 err(1, "SOUND_MIXER_READ_DEVMASK");
161 if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
162 err(1, "SOUND_MIXER_READ_RECMASK");
163 if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
164 err(1, "SOUND_MIXER_READ_RECSRC");
165 orecsrc = recsrc;
167 if (argc == 1 && dusage == 0) {
168 for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
169 if (!((1 << i) & devmask))
170 continue;
171 if (ioctl(baz, MIXER_READ(i),&bar) == -1) {
172 warn("MIXER_READ");
173 continue;
175 if (Sflag || sflag) {
176 printf("%s%s%c%d:%d", n ? " " : "",
177 names[i], Sflag ? ':' : ' ',
178 bar & 0x7f, (bar >> 8) & 0x7f);
179 n++;
180 } else
181 printf("Mixer %-8s is currently set to "
182 "%3d:%d\n", names[i], bar & 0x7f,
183 (bar >> 8) & 0x7f);
185 if (n && recmask)
186 printf(" ");
187 print_recsrc(recsrc, recmask, Sflag || sflag);
188 return (0);
191 argc--;
192 argv++;
194 n = 0;
195 while (argc > 0 && dusage == 0) {
196 if (strcmp("recsrc", *argv) == 0) {
197 drecsrc = 1;
198 argc--;
199 argv++;
200 continue;
201 } else if (strcmp("rec", *argv + 1) == 0) {
202 if (**argv != '+' && **argv != '-' &&
203 **argv != '=' && **argv != '^') {
204 warnx("unknown modifier: %c", **argv);
205 dusage = 1;
206 break;
208 if (argc <= 1) {
209 warnx("no recording device specified");
210 dusage = 1;
211 break;
213 if ((dev = res_name(argv[1], recmask)) == -1) {
214 warnx("unknown recording device: %s", argv[1]);
215 dusage = 1;
216 break;
218 switch (**argv) {
219 case '+':
220 recsrc |= (1 << dev);
221 break;
222 case '-':
223 recsrc &= ~(1 << dev);
224 break;
225 case '=':
226 recsrc = (1 << dev);
227 break;
228 case '^':
229 recsrc ^= (1 << dev);
230 break;
232 drecsrc = 1;
233 argc -= 2;
234 argv += 2;
235 continue;
238 if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0)
239 dev = 0;
240 else if ((dev = res_name(*argv, devmask)) == -1) {
241 warnx("unknown device: %s", *argv);
242 dusage = 1;
243 break;
246 lrel = rrel = 0;
247 if (argc > 1) {
248 m = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
249 if (m > 0) {
250 if (*lstr == '+' || *lstr == '-')
251 lrel = rrel = 1;
252 l = strtol(lstr, NULL, 10);
254 if (m > 1) {
255 if (*rstr == '+' || *rstr == '-')
256 rrel = 1;
257 r = strtol(rstr, NULL, 10);
261 switch (argc > 1 ? m : t) {
262 case 0:
263 if (ioctl(baz, MIXER_READ(dev), &bar) == -1) {
264 warn("MIXER_READ");
265 argc--;
266 argv++;
267 continue;
269 if (Sflag || sflag) {
270 printf("%s%s%c%d:%d", n ? " " : "",
271 names[dev], Sflag ? ':' : ' ',
272 bar & 0x7f, (bar >> 8) & 0x7f);
273 n++;
274 } else
275 printf("Mixer %-8s is currently set to "
276 "%3d:%d\n", names[dev], bar & 0x7f,
277 (bar >> 8) & 0x7f);
279 argc--;
280 argv++;
281 break;
282 case 1:
283 r = l;
284 /* FALLTHROUGH */
285 case 2:
286 if (ioctl(baz, MIXER_READ(dev), &bar) == -1) {
287 warn("MIXER_READ");
288 argc--;
289 argv++;
290 continue;
293 if (lrel)
294 l = (bar & 0x7f) + l;
295 if (rrel)
296 r = ((bar >> 8) & 0x7f) + r;
298 if (l < 0)
299 l = 0;
300 else if (l > 100)
301 l = 100;
302 if (r < 0)
303 r = 0;
304 else if (r > 100)
305 r = 100;
307 if (!Sflag)
308 printf("Setting the mixer %s from %d:%d to "
309 "%d:%d.\n", names[dev], bar & 0x7f,
310 (bar >> 8) & 0x7f, l, r);
312 l |= r << 8;
313 if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
314 warn("WRITE_MIXER");
316 argc -= 2;
317 argv += 2;
318 break;
322 if (dusage) {
323 close(baz);
324 usage(devmask, recmask);
325 /* NOTREACHED */
328 if (orecsrc != recsrc) {
329 if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
330 err(1, "SOUND_MIXER_WRITE_RECSRC");
331 if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
332 err(1, "SOUND_MIXER_READ_RECSRC");
335 if (drecsrc)
336 print_recsrc(recsrc, recmask, Sflag || sflag);
338 close(baz);
340 return (0);