Bug Summary

File:src/usr.bin/sndioctl/sndioctl.c
Warning:line 704, column 25
The left operand of '*' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name sndioctl.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/sndioctl/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/sndioctl/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/sndioctl/sndioctl.c
1/* $OpenBSD: sndioctl.c,v 1.17 2021/12/25 16:25:07 ratchov Exp $ */
2/*
3 * Copyright (c) 2014-2020 Alexandre Ratchov <alex@caoua.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17#include <errno(*__errno()).h>
18#include <poll.h>
19#include <sndio.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <unistd.h>
24
25struct info {
26 struct info *next;
27 struct sioctl_desc desc;
28 unsigned ctladdr;
29#define MODE_IGNORE0 0 /* ignore this value */
30#define MODE_PRINT1 1 /* print-only, don't change value */
31#define MODE_SET2 2 /* set to newval value */
32#define MODE_ADD3 3 /* increase current value by newval */
33#define MODE_SUB4 4 /* decrease current value by newval */
34#define MODE_TOGGLE5 5 /* toggle current value */
35 unsigned mode;
36 int curval, newval;
37};
38
39int cmpdesc(struct sioctl_desc *, struct sioctl_desc *);
40int isdiag(struct info *);
41struct info *vecent(struct info *, char *, int);
42struct info *nextfunc(struct info *);
43struct info *nextpar(struct info *);
44struct info *firstent(struct info *, char *);
45struct info *nextent(struct info *, int);
46int matchpar(struct info *, char *, int);
47int matchent(struct info *, char *, int);
48int ismono(struct info *);
49void print_node(struct sioctl_node *, int);
50void print_desc(struct info *, int);
51void print_num(struct info *);
52void print_ent(struct info *, char *);
53void print_val(struct info *, int);
54void print_par(struct info *, int);
55int parse_name(char **, char *);
56int parse_unit(char **, int *);
57int parse_val(char **, float *);
58int parse_node(char **, char *, int *);
59int parse_modeval(char **, int *, float *);
60void dump(void);
61int cmd(char *);
62void commit(void);
63void list(void);
64void ondesc(void *, struct sioctl_desc *, int);
65void onctl(void *, unsigned, unsigned);
66
67struct sioctl_hdl *hdl;
68struct info *infolist;
69int i_flag = 0, v_flag = 0, m_flag = 0, n_flag = 0, q_flag = 0;
70
71static inline int
72isname(int c)
73{
74 return (c == '_') ||
75 (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
76 (c >= '0' && c <= '9');
77}
78
79static int
80ftoi(float f)
81{
82 return f + 0.5;
83}
84
85/*
86 * compare two sioctl_desc structures, used to sort infolist
87 */
88int
89cmpdesc(struct sioctl_desc *d1, struct sioctl_desc *d2)
90{
91 int res;
92
93 res = strcmp(d1->group, d2->group);
94 if (res != 0)
95 return res;
96 res = strcmp(d1->node0.name, d2->node0.name);
97 if (res != 0)
98 return res;
99 res = d1->type - d2->type;
100 if (res != 0)
101 return res;
102 res = strcmp(d1->func, d2->func);
103 if (res != 0)
104 return res;
105 res = d1->node0.unit - d2->node0.unit;
106 if (d1->type == SIOCTL_SEL6 ||
107 d1->type == SIOCTL_VEC4 ||
108 d1->type == SIOCTL_LIST5) {
109 if (res != 0)
110 return res;
111 res = strcmp(d1->node1.name, d2->node1.name);
112 if (res != 0)
113 return res;
114 res = d1->node1.unit - d2->node1.unit;
115 }
116 return res;
117}
118
119/*
120 * return true of the vector entry is diagonal
121 */
122int
123isdiag(struct info *e)
124{
125 if (e->desc.node0.unit < 0 || e->desc.node1.unit < 0)
126 return 1;
127 return e->desc.node1.unit == e->desc.node0.unit;
128}
129
130/*
131 * find the selector or vector entry with the given name and channels
132 */
133struct info *
134vecent(struct info *i, char *vstr, int vunit)
135{
136 while (i != NULL((void *)0)) {
137 if ((strcmp(i->desc.node1.name, vstr) == 0) &&
138 (vunit < 0 || i->desc.node1.unit == vunit))
139 break;
140 i = i->next;
141 }
142 return i;
143}
144
145/*
146 * skip all parameters with the same group, name, and func
147 */
148struct info *
149nextfunc(struct info *i)
150{
151 char *str, *group, *func;
152
153 group = i->desc.group;
154 func = i->desc.func;
155 str = i->desc.node0.name;
156 for (i = i->next; i != NULL((void *)0); i = i->next) {
157 if (strcmp(i->desc.group, group) != 0 ||
158 strcmp(i->desc.node0.name, str) != 0 ||
159 strcmp(i->desc.func, func) != 0)
160 return i;
161 }
162 return NULL((void *)0);
163}
164
165/*
166 * find the next parameter with the same group, name, func
167 */
168struct info *
169nextpar(struct info *i)
170{
171 char *str, *group, *func;
172 int unit;
173
174 group = i->desc.group;
175 func = i->desc.func;
176 str = i->desc.node0.name;
177 unit = i->desc.node0.unit;
178 for (i = i->next; i != NULL((void *)0); i = i->next) {
179 if (strcmp(i->desc.group, group) != 0 ||
180 strcmp(i->desc.node0.name, str) != 0 ||
181 strcmp(i->desc.func, func) != 0)
182 break;
183 /* XXX: need to check for -1 ? */
184 if (i->desc.node0.unit != unit)
185 return i;
186 }
187 return NULL((void *)0);
188}
189
190/*
191 * return the first vector entry with the given name
192 */
193struct info *
194firstent(struct info *g, char *vstr)
195{
196 char *astr, *group, *func;
197 struct info *i;
198
199 group = g->desc.group;
200 astr = g->desc.node0.name;
201 func = g->desc.func;
202 for (i = g; i != NULL((void *)0); i = i->next) {
203 if (strcmp(i->desc.group, group) != 0 ||
204 strcmp(i->desc.node0.name, astr) != 0 ||
205 strcmp(i->desc.func, func) != 0)
206 break;
207 if (!isdiag(i))
208 continue;
209 if (strcmp(i->desc.node1.name, vstr) == 0)
210 return i;
211 }
212 return NULL((void *)0);
213}
214
215/*
216 * find the next entry of the given vector, if the mono flag
217 * is set then the whole group is searched and off-diagonal entries are
218 * skipped
219 */
220struct info *
221nextent(struct info *i, int mono)
222{
223 char *str, *group, *func;
224 int unit;
225
226 group = i->desc.group;
227 func = i->desc.func;
228 str = i->desc.node0.name;
229 unit = i->desc.node0.unit;
230 for (i = i->next; i != NULL((void *)0); i = i->next) {
231 if (strcmp(i->desc.group, group) != 0 ||
232 strcmp(i->desc.node0.name, str) != 0 ||
233 strcmp(i->desc.func, func) != 0)
234 return NULL((void *)0);
235 if (mono)
236 return i;
237 if (i->desc.node0.unit == unit)
238 return i;
239 }
240 return NULL((void *)0);
241}
242
243/*
244 * return true if parameter matches the given name and channel
245 */
246int
247matchpar(struct info *i, char *astr, int aunit)
248{
249 if (strcmp(i->desc.node0.name, astr) != 0)
55
Assuming the condition is false
56
Taking false branch
250 return 0;
251 if (aunit
56.1
'aunit' is < 0
< 0)
57
Taking true branch
252 return 1;
58
Returning the value 1, which participates in a condition later
253 else if (i->desc.node0.unit < 0) {
254 fprintf(stderr(&__sF[2]), "unit used for parameter with no unit\n");
255 exit(1);
256 }
257 return i->desc.node0.unit == aunit;
258}
259
260/*
261 * return true if selector or vector entry matches the given name and
262 * channel range
263 */
264int
265matchent(struct info *i, char *vstr, int vunit)
266{
267 if (strcmp(i->desc.node1.name, vstr) != 0)
268 return 0;
269 if (vunit < 0)
270 return 1;
271 else if (i->desc.node1.unit < 0) {
272 fprintf(stderr(&__sF[2]), "unit used for parameter with no unit\n");
273 exit(1);
274 }
275 return i->desc.node1.unit == vunit;
276}
277
278/*
279 * return true if the given group can be represented as a signle mono
280 * parameter
281 */
282int
283ismono(struct info *g)
284{
285 struct info *p1, *p2;
286 struct info *e1, *e2;
287
288 p1 = g;
289 switch (g->desc.type) {
290 case SIOCTL_NUM2:
291 case SIOCTL_SW3:
292 for (p2 = g; p2 != NULL((void *)0); p2 = nextpar(p2)) {
293 if (p2->curval != p1->curval)
294 return 0;
295 }
296 break;
297 case SIOCTL_SEL6:
298 case SIOCTL_VEC4:
299 case SIOCTL_LIST5:
300 for (p2 = g; p2 != NULL((void *)0); p2 = nextpar(p2)) {
301 for (e2 = p2; e2 != NULL((void *)0); e2 = nextent(e2, 0)) {
302 if (!isdiag(e2)) {
303 if (e2->curval != 0)
304 return 0;
305 } else {
306 e1 = vecent(p1,
307 e2->desc.node1.name,
308 p1->desc.node0.unit);
309 if (e1 == NULL((void *)0))
310 continue;
311 if (e1->curval != e2->curval)
312 return 0;
313 }
314 }
315 }
316 break;
317 }
318 return 1;
319}
320
321/*
322 * print a sub-stream, eg. "spkr[4]"
323 */
324void
325print_node(struct sioctl_node *c, int mono)
326{
327 printf("%s", c->name);
328 if (!mono && c->unit >= 0)
329 printf("[%d]", c->unit);
330}
331
332/*
333 * print info about the parameter
334 */
335void
336print_desc(struct info *p, int mono)
337{
338 struct info *e;
339 int more;
340
341 switch (p->desc.type) {
342 case SIOCTL_NUM2:
343 case SIOCTL_SW3:
344 printf("*");
345 break;
346 case SIOCTL_SEL6:
347 case SIOCTL_VEC4:
348 case SIOCTL_LIST5:
349 more = 0;
350 for (e = p; e != NULL((void *)0); e = nextent(e, mono)) {
351 if (mono) {
352 if (!isdiag(e))
353 continue;
354 if (e != firstent(p, e->desc.node1.name))
355 continue;
356 }
357 if (more)
358 printf(",");
359 print_node(&e->desc.node1, mono);
360 if (p->desc.type != SIOCTL_SEL6)
361 printf(":*");
362 more = 1;
363 }
364 }
365}
366
367void
368print_num(struct info *p)
369{
370 if (p->desc.maxval == 1)
371 printf("%d", p->curval);
372 else {
373 /*
374 * For now, maxval is always 127 or 255,
375 * so three decimals is always ideal.
376 */
377 printf("%.3f", p->curval / (float)p->desc.maxval);
378 }
379}
380
381/*
382 * print a single control
383 */
384void
385print_ent(struct info *e, char *comment)
386{
387 if (e->desc.group[0] != 0) {
388 printf("%s", e->desc.group);
389 printf("/");
390 }
391 print_node(&e->desc.node0, 0);
392 printf(".%s=", e->desc.func);
393 switch (e->desc.type) {
394 case SIOCTL_NONE0:
395 printf("<removed>\n");
396 break;
397 case SIOCTL_SEL6:
398 case SIOCTL_VEC4:
399 case SIOCTL_LIST5:
400 print_node(&e->desc.node1, 0);
401 printf(":");
402 /* FALLTHROUGH */
403 case SIOCTL_SW3:
404 case SIOCTL_NUM2:
405 print_num(e);
406 }
407 if (comment)
408 printf("\t# %s", comment);
409 printf("\n");
410}
411
412/*
413 * print parameter value
414 */
415void
416print_val(struct info *p, int mono)
417{
418 struct info *e;
419 int more;
420
421 switch (p->desc.type) {
422 case SIOCTL_NUM2:
423 case SIOCTL_SW3:
424 print_num(p);
425 break;
426 case SIOCTL_SEL6:
427 case SIOCTL_VEC4:
428 case SIOCTL_LIST5:
429 more = 0;
430 for (e = p; e != NULL((void *)0); e = nextent(e, mono)) {
431 if (mono) {
432 if (!isdiag(e))
433 continue;
434 if (e != firstent(p, e->desc.node1.name))
435 continue;
436 }
437 if (e->desc.maxval == 1) {
438 if (e->curval) {
439 if (more)
440 printf(",");
441 print_node(&e->desc.node1, mono);
442 more = 1;
443 }
444 } else {
445 if (more)
446 printf(",");
447 print_node(&e->desc.node1, mono);
448 printf(":");
449 print_num(e);
450 more = 1;
451 }
452 }
453 }
454}
455
456/*
457 * print ``<parameter>=<value>'' string (including '\n')
458 */
459void
460print_par(struct info *p, int mono)
461{
462 if (!n_flag) {
463 if (p->desc.group[0] != 0) {
464 printf("%s", p->desc.group);
465 printf("/");
466 }
467 print_node(&p->desc.node0, mono);
468 printf(".%s=", p->desc.func);
469 }
470 if (i_flag)
471 print_desc(p, mono);
472 else
473 print_val(p, mono);
474 printf("\n");
475}
476
477/*
478 * parse a stream name or parameter name
479 */
480int
481parse_name(char **line, char *name)
482{
483 char *p = *line;
484 unsigned len = 0;
485
486 if (!isname(*p)) {
27
Taking false branch
487 fprintf(stderr(&__sF[2]), "letter or digit expected near '%s'\n", p);
488 return 0;
489 }
490 while (isname(*p)) {
28
Loop condition is true. Entering loop body
30
Loop condition is false. Execution continues on line 499
491 if (len >= SIOCTL_NAMEMAX12 - 1) {
29
Taking false branch
492 name[SIOCTL_NAMEMAX12 - 1] = '\0';
493 fprintf(stderr(&__sF[2]), "%s...: too long\n", name);
494 return 0;
495 }
496 name[len++] = *p;
497 p++;
498 }
499 name[len] = '\0';
500 *line = p;
501 return 1;
31
Returning the value 1, which participates in a condition later
502}
503
504/*
505 * parse a decimal integer
506 */
507int
508parse_unit(char **line, int *num)
509{
510 char *p = *line;
511 unsigned int val;
512 int n;
513
514 if (sscanf(p, "%u%n", &val, &n) != 1) {
515 fprintf(stderr(&__sF[2]), "number expected near '%s'\n", p);
516 return 0;
517 }
518 if (val >= 255) {
519 fprintf(stderr(&__sF[2]), "%d: too large\n", val);
520 return 0;
521 }
522 *num = val;
523 *line = p + n;
524 return 1;
525}
526
527int
528parse_val(char **line, float *num)
529{
530 char *p = *line;
531 float val;
532 int n;
533
534 if (sscanf(p, "%g%n", &val, &n) != 1) {
535 fprintf(stderr(&__sF[2]), "number expected near '%s'\n", p);
536 return 0;
537 }
538 if (val < 0 || val > 1) {
539 fprintf(stderr(&__sF[2]), "%g: expected number between 0 and 1\n", val);
540 return 0;
541 }
542 *num = val;
543 *line = p + n;
544 return 1;
545}
546
547/*
548 * parse a sub-stream, eg. "spkr[7]"
549 */
550int
551parse_node(char **line, char *str, int *unit)
552{
553 char *p = *line;
554
555 if (!parse_name(&p, str))
19
Taking false branch
556 return 0;
557 if (*p != '[') {
20
Taking true branch
558 *unit = -1;
559 *line = p;
560 return 1;
21
Returning the value 1, which participates in a condition later
561 }
562 p++;
563 if (!parse_unit(&p, unit))
564 return 0;
565 if (*p != ']') {
566 fprintf(stderr(&__sF[2]), "']' expected near '%s'\n", p);
567 return 0;
568 }
569 p++;
570 *line = p;
571 return 1;
572}
573
574/*
575 * parse a decimal prefixed by the optional mode
576 */
577int
578parse_modeval(char **line, int *rmode, float *rval)
579{
580 char *p = *line;
581 unsigned mode;
582
583 switch (*p) {
46
Control jumps to 'case 33:' at line 592
584 case '+':
585 mode = MODE_ADD3;
586 p++;
587 break;
588 case '-':
589 mode = MODE_SUB4;
590 p++;
591 break;
592 case '!':
593 mode = MODE_TOGGLE5;
594 p++;
595 break;
47
Execution continues on line 599
596 default:
597 mode = MODE_SET2;
598 }
599 if (mode
47.1
'mode' is equal to MODE_TOGGLE
!= MODE_TOGGLE5) {
48
Taking false branch
600 if (!parse_val(&p, rval))
601 return 0;
602 }
603 *line = p;
604 *rmode = mode;
605 return 1;
49
Returning without writing to '*rval'
50
Returning the value 1, which participates in a condition later
606}
607
608/*
609 * dump the whole controls list, useful for debugging
610 */
611void
612dump(void)
613{
614 struct info *i;
615
616 for (i = infolist; i != NULL((void *)0); i = i->next) {
617 printf("%03u:", i->ctladdr);
618 print_node(&i->desc.node0, 0);
619 printf(".%s", i->desc.func);
620 printf("=");
621 switch (i->desc.type) {
622 case SIOCTL_NUM2:
623 case SIOCTL_SW3:
624 printf("0..%d (%u)", i->desc.maxval, i->curval);
625 break;
626 case SIOCTL_SEL6:
627 print_node(&i->desc.node1, 0);
628 break;
629 case SIOCTL_VEC4:
630 case SIOCTL_LIST5:
631 print_node(&i->desc.node1, 0);
632 printf(":0..%d (%u)", i->desc.maxval, i->curval);
633 }
634 printf("\n");
635 }
636}
637
638/*
639 * parse and execute a command ``<parameter>[=<value>]''
640 */
641int
642cmd(char *line)
643{
644 char *pos, *group;
645 struct info *i, *e, *g;
646 char func[SIOCTL_NAMEMAX12];
647 char astr[SIOCTL_NAMEMAX12], vstr[SIOCTL_NAMEMAX12];
648 int aunit, vunit;
649 unsigned npar = 0, nent = 0;
650 int comma, mode;
651 float val;
15
'val' declared without an initial value
652
653 pos = strrchr(line, '/');
654 if (pos != NULL((void *)0)) {
16
Assuming 'pos' is equal to NULL
17
Taking false branch
655 group = line;
656 pos[0] = 0;
657 pos++;
658 } else {
659 group = "";
660 pos = line;
661 }
662 if (!parse_node(&pos, astr, &aunit))
18
Calling 'parse_node'
22
Returning from 'parse_node'
23
Taking false branch
663 return 0;
664 if (*pos != '.') {
24
Assuming the condition is false
25
Taking false branch
665 fprintf(stderr(&__sF[2]), "'.' expected near '%s'\n", pos);
666 return 0;
667 }
668 pos++;
669 if (!parse_name(&pos, func))
26
Calling 'parse_name'
32
Returning from 'parse_name'
33
Taking false branch
670 return 0;
671 for (g = infolist;; g = g->next) {
34
Loop condition is true. Entering loop body
672 if (g == NULL((void *)0)) {
35
Assuming 'g' is not equal to NULL
36
Taking false branch
673 fprintf(stderr(&__sF[2]), "%s.%s: no such control\n", astr, func);
674 return 0;
675 }
676 if (strcmp(g->desc.group, group) == 0 &&
39
Taking true branch
677 strcmp(g->desc.func, func) == 0 &&
37
Assuming the condition is true
678 strcmp(g->desc.node0.name, astr) == 0)
38
Assuming the condition is true
679 break;
40
Execution continues on line 681
680 }
681 g->mode = MODE_PRINT1;
682 if (*pos != '=') {
41
Assuming the condition is false
42
Taking false branch
683 if (*pos != '\0') {
684 fprintf(stderr(&__sF[2]), "junk at end of command\n");
685 return 0;
686 }
687 return 1;
688 }
689 pos++;
690 if (i_flag
42.1
'i_flag' is 0
) {
43
Taking false branch
691 printf("can't set values in info mode\n");
692 return 0;
693 }
694 npar = 0;
695 switch (g->desc.type) {
44
Control jumps to 'case 3:' at line 697
696 case SIOCTL_NUM2:
697 case SIOCTL_SW3:
698 if (!parse_modeval(&pos, &mode, &val))
45
Calling 'parse_modeval'
51
Returning from 'parse_modeval'
52
Taking false branch
699 return 0;
700 for (i = g; i
52.1
'i' is not equal to NULL
!= NULL((void *)0); i = nextpar(i)) {
53
Loop condition is true. Entering loop body
701 if (!matchpar(i, astr, aunit))
54
Calling 'matchpar'
59
Returning from 'matchpar'
60
Taking false branch
702 continue;
703 i->mode = mode;
704 i->newval = ftoi(val * i->desc.maxval);
61
The left operand of '*' is a garbage value
705 npar++;
706 }
707 break;
708 case SIOCTL_SEL6:
709 if (*pos == '\0') {
710 fprintf(stderr(&__sF[2]), "%s.%s: expects value\n", astr, func);
711 exit(1);
712 }
713 /* FALLTROUGH */
714 case SIOCTL_VEC4:
715 case SIOCTL_LIST5:
716 for (i = g; i != NULL((void *)0); i = nextpar(i)) {
717 if (!matchpar(i, astr, aunit))
718 continue;
719 for (e = i; e != NULL((void *)0); e = nextent(e, 0)) {
720 e->newval = 0;
721 e->mode = MODE_SET2;
722 }
723 npar++;
724 }
725 comma = 0;
726 for (;;) {
727 if (*pos == '\0')
728 break;
729 if (comma) {
730 if (*pos != ',')
731 break;
732 pos++;
733 }
734 if (!parse_node(&pos, vstr, &vunit))
735 return 0;
736 if (*pos == ':') {
737 pos++;
738 if (!parse_modeval(&pos, &mode, &val))
739 return 0;
740 } else {
741 val = 1.;
742 mode = MODE_SET2;
743 }
744 nent = 0;
745 for (i = g; i != NULL((void *)0); i = nextpar(i)) {
746 if (!matchpar(i, astr, aunit))
747 continue;
748 for (e = i; e != NULL((void *)0); e = nextent(e, 0)) {
749 if (matchent(e, vstr, vunit)) {
750 e->newval = ftoi(val * e->desc.maxval);
751 e->mode = mode;
752 nent++;
753 }
754 }
755 }
756 if (nent == 0) {
757 /* XXX: use print_node()-like routine */
758 fprintf(stderr(&__sF[2]), "%s[%d]: invalid value\n", vstr, vunit);
759 print_par(g, 0);
760 exit(1);
761 }
762 comma = 1;
763 }
764 }
765 if (npar == 0) {
766 fprintf(stderr(&__sF[2]), "%s: invalid parameter\n", line);
767 exit(1);
768 }
769 if (*pos != '\0') {
770 printf("%s: junk at end of command\n", pos);
771 exit(1);
772 }
773 return 1;
774}
775
776/*
777 * write the controls with the ``set'' flag on the device
778 */
779void
780commit(void)
781{
782 struct info *i;
783 int val;
784
785 for (i = infolist; i != NULL((void *)0); i = i->next) {
786 val = 0xdeadbeef;
787 switch (i->mode) {
788 case MODE_IGNORE0:
789 case MODE_PRINT1:
790 continue;
791 case MODE_SET2:
792 val = i->newval;
793 break;
794 case MODE_ADD3:
795 val = i->curval + i->newval;
796 if (val > i->desc.maxval)
797 val = i->desc.maxval;
798 break;
799 case MODE_SUB4:
800 val = i->curval - i->newval;
801 if (val < 0)
802 val = 0;
803 break;
804 case MODE_TOGGLE5:
805 val = i->curval ? 0 : i->desc.maxval;
806 }
807 sioctl_setval(hdl, i->ctladdr, val);
808 i->curval = val;
809 }
810}
811
812/*
813 * print all parameters
814 */
815void
816list(void)
817{
818 struct info *p, *g;
819
820 for (g = infolist; g != NULL((void *)0); g = nextfunc(g)) {
821 if (g->mode == MODE_IGNORE0)
822 continue;
823 if (i_flag) {
824 if (v_flag) {
825 for (p = g; p != NULL((void *)0); p = nextpar(p))
826 print_par(p, 0);
827 } else
828 print_par(g, 1);
829 } else {
830 if (v_flag || !ismono(g)) {
831 for (p = g; p != NULL((void *)0); p = nextpar(p))
832 print_par(p, 0);
833 } else
834 print_par(g, 1);
835 }
836 }
837}
838
839/*
840 * register a new knob/button, called from the poll() loop. this may be
841 * called when label string changes, in which case we update the
842 * existing label widged rather than inserting a new one.
843 */
844void
845ondesc(void *arg, struct sioctl_desc *d, int curval)
846{
847 struct info *i, **pi;
848 int cmp;
849
850 if (d == NULL((void *)0))
851 return;
852
853 /*
854 * delete control
855 */
856 for (pi = &infolist; (i = *pi) != NULL((void *)0); pi = &i->next) {
857 if (d->addr == i->desc.addr) {
858 if (m_flag)
859 print_ent(i, "deleted");
860 *pi = i->next;
861 free(i);
862 break;
863 }
864 }
865
866 switch (d->type) {
867 case SIOCTL_NUM2:
868 case SIOCTL_SW3:
869 case SIOCTL_VEC4:
870 case SIOCTL_LIST5:
871 case SIOCTL_SEL6:
872 break;
873 default:
874 return;
875 }
876
877 /*
878 * find the right position to insert the new widget
879 */
880 for (pi = &infolist; (i = *pi) != NULL((void *)0); pi = &i->next) {
881 cmp = cmpdesc(d, &i->desc);
882 if (cmp == 0) {
883 fprintf(stderr(&__sF[2]), "fatal: duplicate control:\n");
884 print_ent(i, "duplicate");
885 exit(1);
886 }
887 if (cmp < 0)
888 break;
889 }
890 i = malloc(sizeof(struct info));
891 if (i == NULL((void *)0)) {
892 perror("malloc");
893 exit(1);
894 }
895 i->desc = *d;
896 i->ctladdr = d->addr;
897 i->curval = i->newval = curval;
898 i->mode = MODE_IGNORE0;
899 i->next = *pi;
900 *pi = i;
901 if (m_flag)
902 print_ent(i, "added");
903}
904
905/*
906 * update a knob/button state, called from the poll() loop
907 */
908void
909onctl(void *arg, unsigned addr, unsigned val)
910{
911 struct info *i, *j;
912
913 i = infolist;
914 for (;;) {
915 if (i == NULL((void *)0))
916 return;
917 if (i->ctladdr == addr)
918 break;
919 i = i->next;
920 }
921
922 if (i->curval == val) {
923 print_ent(i, "eq");
924 return;
925 }
926
927 if (i->desc.type == SIOCTL_SEL6) {
928 for (j = infolist; j != NULL((void *)0); j = j->next) {
929 if (strcmp(i->desc.group, j->desc.group) != 0 ||
930 strcmp(i->desc.node0.name, j->desc.node0.name) != 0 ||
931 strcmp(i->desc.func, j->desc.func) != 0 ||
932 i->desc.node0.unit != j->desc.node0.unit)
933 continue;
934 j->curval = (i->ctladdr == j->ctladdr);
935 }
936 } else
937 i->curval = val;
938
939 if (m_flag)
940 print_ent(i, "changed");
941}
942
943int
944main(int argc, char **argv)
945{
946 char *devname = SIO_DEVANY"default";
947 int i, c, d_flag = 0;
948 struct info *g;
949 struct pollfd *pfds;
950 int nfds, revents;
951
952 while ((c = getopt(argc, argv, "df:imnqv")) != -1) {
1
Assuming the condition is false
2
Loop condition is false. Execution continues on line 981
953 switch (c) {
954 case 'd':
955 d_flag = 1;
956 break;
957 case 'f':
958 devname = optarg;
959 break;
960 case 'i':
961 i_flag = 1;
962 break;
963 case 'm':
964 m_flag = 1;
965 break;
966 case 'n':
967 n_flag = 1;
968 break;
969 case 'q':
970 q_flag = 1;
971 break;
972 case 'v':
973 v_flag++;
974 break;
975 default:
976 fprintf(stderr(&__sF[2]), "usage: sndioctl "
977 "[-dimnqv] [-f device] [command ...]\n");
978 exit(1);
979 }
980 }
981 argc -= optind;
982 argv += optind;
983
984 hdl = sioctl_open(devname, SIOCTL_READ0x100 | SIOCTL_WRITE0x200, 0);
985 if (hdl == NULL((void *)0)) {
3
Assuming 'hdl' is not equal to NULL
4
Taking false branch
986 fprintf(stderr(&__sF[2]), "%s: can't open control device\n", devname);
987 exit(1);
988 }
989
990 if (pledge("stdio audio", NULL((void *)0)) == -1) {
5
Assuming the condition is false
6
Taking false branch
991 fprintf(stderr(&__sF[2]), "%s: pledge: %s\n", getprogname(),
992 strerror(errno(*__errno())));
993 exit(1);
994 }
995
996 if (!sioctl_ondesc(hdl, ondesc, NULL((void *)0))) {
7
Assuming the condition is false
8
Taking false branch
997 fprintf(stderr(&__sF[2]), "%s: can't get device description\n", devname);
998 exit(1);
999 }
1000 sioctl_onval(hdl, onctl, NULL((void *)0));
1001
1002 if (d_flag
8.1
'd_flag' is 0
) {
9
Taking false branch
1003 if (argc > 0) {
1004 fprintf(stderr(&__sF[2]),
1005 "commands are not allowed with -d option\n");
1006 exit(1);
1007 }
1008 dump();
1009 } else {
1010 if (argc == 0) {
10
Assuming 'argc' is not equal to 0
11
Taking false branch
1011 for (g = infolist; g != NULL((void *)0); g = nextfunc(g))
1012 g->mode = MODE_PRINT1;
1013 } else {
1014 for (i = 0; i < argc; i++) {
12
Assuming 'i' is < 'argc'
13
Loop condition is true. Entering loop body
1015 if (!cmd(argv[i]))
14
Calling 'cmd'
1016 return 1;
1017 }
1018 }
1019 commit();
1020 if (!q_flag)
1021 list();
1022 }
1023 if (m_flag) {
1024 pfds = malloc(sizeof(struct pollfd) * sioctl_nfds(hdl));
1025 if (pfds == NULL((void *)0)) {
1026 perror("malloc");
1027 exit(1);
1028 }
1029 for (;;) {
1030 fflush(stdout(&__sF[1]));
1031 nfds = sioctl_pollfd(hdl, pfds, POLLIN0x0001);
1032 if (nfds == 0)
1033 break;
1034 while (poll(pfds, nfds, -1) < 0) {
1035 if (errno(*__errno()) != EINTR4) {
1036 perror("poll");
1037 exit(1);
1038 }
1039 }
1040 revents = sioctl_revents(hdl, pfds);
1041 if (revents & POLLHUP0x0010) {
1042 fprintf(stderr(&__sF[2]), "disconnected\n");
1043 break;
1044 }
1045 }
1046 free(pfds);
1047 }
1048 sioctl_close(hdl);
1049 return 0;
1050}