Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name sndioctl.c -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 -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -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/llvm16/lib/clang/16 -internal-isystem /usr/local/llvm16/lib/clang/16/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 -fcf-protection=branch -fno-jump-tables -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/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.bin/sndioctl/sndioctl.c
1/* $OpenBSD: sndioctl.c,v 1.19 2023/01/31 21:38:01 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)
250 return 0;
251 if (aunit < 0)
252 return 1;
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)) {
487 fprintf(stderr(&__sF[2]), "letter or digit expected near '%s'\n", p);
488 return 0;
489 }
490 while (isname(*p)) {
491 if (len >= SIOCTL_NAMEMAX12 - 1) {
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;
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))
556 return 0;
557 if (*p != '[') {
558 *unit = -1;
559 *line = p;
560 return 1;
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) {
44
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;
596 default:
597 mode = MODE_SET2;
598 }
599 if (mode
45.1
'mode' is equal to MODE_TOGGLE
!= MODE_TOGGLE5) {
45
Execution continues on line 599
46
Taking false branch
600 if (!parse_val(&p, rval))
601 return 0;
602 }
603 *line = p;
604 *rmode = mode;
605 return 1;
47
Returning without writing to '*rval'
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
Taking false branch
663 return 0;
664 if (*pos != '.') {
19
Assuming the condition is false
20
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))
21
Taking false branch
670 return 0;
671 for (g = infolist;; g = g->next) {
22
Loop condition is true. Entering loop body
672 if (g == NULL((void *)0)) {
23
Assuming 'g' is not equal to NULL
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 &&
26
Taking true branch
677 strcmp(g->desc.func, func) == 0 &&
24
Assuming the condition is true
678 strcmp(g->desc.node0.name, astr) == 0)
25
Assuming the condition is true
679 break;
680 }
681 g->mode = MODE_PRINT1;
27
Execution continues on line 681
682 if (*pos != '=') {
28
Assuming the condition is false
29
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
29.1
'i_flag' is 0
) {
30
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) {
31
Control jumps to 'case 4:' at line 714
696 case SIOCTL_NUM2:
697 case SIOCTL_SW3:
698 if (!parse_modeval(&pos, &mode, &val))
699 return 0;
700 for (i = g; i != NULL((void *)0); i = nextpar(i)) {
701 if (!matchpar(i, astr, aunit))
702 continue;
703 i->mode = mode;
704 i->newval = ftoi(val * i->desc.maxval);
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 /* FALLTHROUGH */
714 case SIOCTL_VEC4:
715 case SIOCTL_LIST5:
716 for (i = g; i
31.1
'i' is not equal to NULL
!= NULL((void *)0); i = nextpar(i)) {
32
Loop condition is true. Entering loop body
34
Execution continues on line 716
35
Loop condition is false. Execution continues on line 725
717 if (!matchpar(i, astr, aunit))
33
Taking true branch
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 (;;) {
36
Loop condition is true. Entering loop body
727 if (*pos == '\0')
37
Assuming the condition is false
38
Taking false branch
728 break;
729 if (comma
38.1
'comma' is 0
) {
39
Taking false branch
730 if (*pos != ',')
731 break;
732 pos++;
733 }
734 if (!parse_node(&pos, vstr, &vunit))
40
Taking false branch
735 return 0;
736 if (*pos == ':') {
41
Assuming the condition is true
42
Taking true branch
737 pos++;
738 if (!parse_modeval(&pos, &mode, &val))
43
Calling 'parse_modeval'
48
Returning from 'parse_modeval'
49
Taking false branch
739 return 0;
740 } else {
741 val = 1.;
742 mode = MODE_SET2;
743 }
744 nent = 0;
745 for (i = g; i
49.1
'i' is not equal to NULL
!= NULL((void *)0); i = nextpar(i)) {
50
Loop condition is true. Entering loop body
746 if (!matchpar(i, astr, aunit))
51
Taking false branch
747 continue;
748 for (e = i; e
51.1
'e' is not equal to NULL
!= NULL((void *)0); e = nextent(e, 0)) {
52
Loop condition is true. Entering loop body
749 if (matchent(e, vstr, vunit)) {
53
Taking true branch
750 e->newval = ftoi(val * e->desc.maxval);
54
The left operand of '*' is a garbage value
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 widget 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}