Annotation of src/usr.bin/sndioctl/sndioctl.c, Revision 1.2
1.2 ! ratchov 1: /* $OpenBSD: sndioctl.c,v 1.1 2020/02/26 13:58:48 ratchov Exp $ */
1.1 ratchov 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.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:
25: struct info {
26: struct info *next;
27: struct sioctl_desc desc;
28: unsigned ctladdr;
29: #define MODE_IGNORE 0 /* ignore this value */
30: #define MODE_PRINT 1 /* print-only, don't change value */
31: #define MODE_SET 2 /* set to newval value */
32: #define MODE_ADD 3 /* increase current value by newval */
33: #define MODE_SUB 4 /* decrease current value by newval */
34: #define MODE_TOGGLE 5 /* toggle current value */
35: unsigned mode;
36: int curval, newval;
37: };
38:
39: int cmpdesc(struct sioctl_desc *, struct sioctl_desc *);
40: int isdiag(struct info *);
41: struct info *vecent(struct info *, char *, int);
42: struct info *nextfunc(struct info *);
43: struct info *nextpar(struct info *);
44: struct info *firstent(struct info *, char *);
45: struct info *nextent(struct info *, int);
46: int matchpar(struct info *, char *, int);
47: int matchent(struct info *, char *, int);
48: int ismono(struct info *);
49: void print_node(struct sioctl_node *, int);
50: void print_desc(struct info *, int);
51: void print_val(struct info *, int);
52: void print_par(struct info *, int, char *);
53: int parse_name(char **, char *);
54: int parse_unit(char **, unsigned int *);
55: int parse_val(char **, float *);
56: int parse_node(char **, char *, int *);
57: int parse_modeval(char **, int *, float *);
58: void dump(void);
59: int cmd(char *);
60: void commit(void);
61: void list(void);
62: void ondesc(void *, struct sioctl_desc *, int);
63: void onctl(void *, unsigned, unsigned);
64:
65: struct sioctl_hdl *hdl;
66: struct info *infolist;
67: int i_flag = 0, v_flag = 0, m_flag = 0;
68:
69: static inline int
70: isname_first(int c)
71: {
72: return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
73: }
74:
75: static inline int
76: isname_next(int c)
77: {
78: return isname_first(c) || (c >= '0' && c <= '9') || (c == '_');
79: }
80:
81: static int
82: ftoi(float f)
83: {
84: return f + 0.5;
85: }
86:
87: /*
88: * compare two sioctl_desc structures, used to sort infolist
89: */
90: int
91: cmpdesc(struct sioctl_desc *d1, struct sioctl_desc *d2)
92: {
93: int res;
94:
95: res = strcmp(d1->group, d2->group);
96: if (res != 0)
97: return res;
98: res = strcmp(d1->node0.name, d2->node0.name);
99: if (res != 0)
100: return res;
101: res = d1->type - d2->type;
102: if (res != 0)
103: return res;
104: res = strcmp(d1->func, d2->func);
105: if (res != 0)
106: return res;
107: res = d1->node0.unit - d2->node0.unit;
108: if (d1->type == SIOCTL_VEC ||
109: d1->type == SIOCTL_LIST) {
110: if (res != 0)
111: return res;
112: res = strcmp(d1->node1.name, d2->node1.name);
113: if (res != 0)
114: return res;
115: res = d1->node1.unit - d2->node1.unit;
116: }
117: return res;
118: }
119:
120: /*
121: * return true of the vector entry is diagonal
122: */
123: int
124: isdiag(struct info *e)
125: {
126: if (e->desc.node0.unit < 0 || e->desc.node1.unit < 0)
127: return 1;
128: return e->desc.node1.unit == e->desc.node0.unit;
129: }
130:
131: /*
132: * find the selector or vector entry with the given name and channels
133: */
134: struct info *
135: vecent(struct info *i, char *vstr, int vunit)
136: {
137: while (i != NULL) {
138: if ((strcmp(i->desc.node1.name, vstr) == 0) &&
139: (vunit < 0 || i->desc.node1.unit == vunit))
140: break;
141: i = i->next;
142: }
143: return i;
144: }
145:
146: /*
147: * skip all parameters with the same group, name, and func
148: */
149: struct info *
150: nextfunc(struct info *i)
151: {
152: char *str, *group, *func;
153:
154: group = i->desc.group;
155: func = i->desc.func;
156: str = i->desc.node0.name;
157: for (i = i->next; i != NULL; i = i->next) {
158: if (strcmp(i->desc.group, group) != 0 ||
159: strcmp(i->desc.node0.name, str) != 0 ||
160: strcmp(i->desc.func, func) != 0)
161: return i;
162: }
163: return NULL;
164: }
165:
166: /*
167: * find the next parameter with the same group, name, func
168: */
169: struct info *
170: nextpar(struct info *i)
171: {
172: char *str, *group, *func;
173: int unit;
174:
175: group = i->desc.group;
176: func = i->desc.func;
177: str = i->desc.node0.name;
178: unit = i->desc.node0.unit;
179: for (i = i->next; i != NULL; i = i->next) {
180: if (strcmp(i->desc.group, group) != 0 ||
181: strcmp(i->desc.node0.name, str) != 0 ||
182: strcmp(i->desc.func, func) != 0)
183: break;
184: /* XXX: need to check for -1 ? */
185: if (i->desc.node0.unit != unit)
186: return i;
187: }
188: return NULL;
189: }
190:
191: /*
192: * return the first vector entry with the given name
193: */
194: struct info *
195: firstent(struct info *g, char *vstr)
196: {
197: char *astr, *group, *func;
198: struct info *i;
199:
200: group = g->desc.group;
201: astr = g->desc.node0.name;
202: func = g->desc.func;
203: for (i = g; i != NULL; i = i->next) {
204: if (strcmp(i->desc.group, group) != 0 ||
205: strcmp(i->desc.node0.name, astr) != 0 ||
206: strcmp(i->desc.func, func) != 0)
207: break;
208: if (!isdiag(i))
209: continue;
210: if (strcmp(i->desc.node1.name, vstr) == 0)
211: return i;
212: }
213: return NULL;
214: }
215:
216: /*
217: * find the next entry of the given vector, if the mono flag
218: * is set then the whole group is searched and off-diagonal entries are
219: * skipped
220: */
221: struct info *
222: nextent(struct info *i, int mono)
223: {
224: char *str, *group, *func;
225: int unit;
226:
227: group = i->desc.group;
228: func = i->desc.func;
229: str = i->desc.node0.name;
230: unit = i->desc.node0.unit;
231: for (i = i->next; i != NULL; i = i->next) {
232: if (strcmp(i->desc.group, group) != 0 ||
233: strcmp(i->desc.node0.name, str) != 0 ||
234: strcmp(i->desc.func, func) != 0)
235: return NULL;
236: if (mono)
237: return i;
238: if (i->desc.node0.unit == unit)
239: return i;
240: }
241: return NULL;
242: }
243:
244: /*
245: * return true if parameter matches the given name and channel
246: */
247: int
248: matchpar(struct info *i, char *astr, int aunit)
249: {
250: if (strcmp(i->desc.node0.name, astr) != 0)
251: return 0;
252: if (aunit < 0)
253: return 1;
254: else if (i->desc.node0.unit < 0) {
255: fprintf(stderr, "unit used for parameter with no unit\n");
256: exit(1);
257: }
258: return i->desc.node0.unit == aunit;
259: }
260:
261: /*
262: * return true if selector or vector entry matches the given name and
263: * channel range
264: */
265: int
266: matchent(struct info *i, char *vstr, int vunit)
267: {
268: if (strcmp(i->desc.node1.name, vstr) != 0)
269: return 0;
270: if (vunit < 0)
271: return 1;
272: else if (i->desc.node1.unit < 0) {
273: fprintf(stderr, "unit used for parameter with no unit\n");
274: exit(1);
275: }
276: return i->desc.node1.unit == vunit;
277: }
278:
279: /*
280: * return true if the given group can be represented as a signle mono
281: * parameter
282: */
283: int
284: ismono(struct info *g)
285: {
286: struct info *p1, *p2;
287: struct info *e1, *e2;
288:
289: p1 = g;
290: switch (g->desc.type) {
291: case SIOCTL_NUM:
292: case SIOCTL_SW:
293: for (p2 = g; p2 != NULL; p2 = nextpar(p2)) {
294: if (p2->curval != p1->curval)
295: return 0;
296: }
297: break;
298: case SIOCTL_VEC:
299: case SIOCTL_LIST:
300: for (p2 = g; p2 != NULL; p2 = nextpar(p2)) {
301: for (e2 = p2; e2 != NULL; 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)
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: */
324: void
325: print_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: */
335: void
336: print_desc(struct info *p, int mono)
337: {
338: struct info *e;
339: int more;
340:
341: switch (p->desc.type) {
342: case SIOCTL_NUM:
343: case SIOCTL_SW:
344: printf("*");
345: break;
346: case SIOCTL_VEC:
347: case SIOCTL_LIST:
348: more = 0;
349: for (e = p; e != NULL; e = nextent(e, mono)) {
350: if (mono) {
351: if (!isdiag(e))
352: continue;
353: if (e != firstent(p, e->desc.node1.name))
354: continue;
355: }
356: if (more)
357: printf(",");
358: print_node(&e->desc.node1, mono);
359: printf(":*");
360: more = 1;
361: }
362: }
363: }
364:
365: /*
366: * print parameter value
367: */
368: void
369: print_val(struct info *p, int mono)
370: {
371: struct info *e;
372: int more;
373:
374: switch (p->desc.type) {
375: case SIOCTL_NUM:
376: case SIOCTL_SW:
377: printf("%.2g", p->curval / (float)p->desc.maxval);
378: break;
379: case SIOCTL_VEC:
380: case SIOCTL_LIST:
381: more = 0;
382: for (e = p; e != NULL; e = nextent(e, mono)) {
383: if (mono) {
384: if (!isdiag(e))
385: continue;
386: if (e != firstent(p, e->desc.node1.name))
387: continue;
388: }
389: if (more)
390: printf(",");
391: print_node(&e->desc.node1, mono);
392: printf(":%.2g", e->curval / (float)e->desc.maxval);
393: more = 1;
394: }
395: }
396: }
397:
398: /*
399: * print ``<parameter>=<value>'' string (including '\n')
400: */
401: void
402: print_par(struct info *p, int mono, char *comment)
403: {
404: if (p->desc.group[0] != 0) {
405: printf("%s", p->desc.group);
406: printf("/");
407: }
408: print_node(&p->desc.node0, mono);
409: printf(".%s=", p->desc.func);
410: if (i_flag)
411: print_desc(p, mono);
412: else
413: print_val(p, mono);
414: if (comment)
415: printf(" # %s", comment);
416: printf("\n");
417: }
418:
419: /*
420: * parse a stream name or parameter name
421: */
422: int
423: parse_name(char **line, char *name)
424: {
425: char *p = *line;
426: unsigned len = 0;
427:
428: if (!isname_first(*p)) {
429: fprintf(stderr, "letter expected near '%s'\n", p);
430: return 0;
431: }
432: while (isname_next(*p)) {
433: if (len >= SIOCTL_NAMEMAX - 1) {
434: name[SIOCTL_NAMEMAX - 1] = '\0';
435: fprintf(stderr, "%s...: too long\n", name);
436: return 0;
437: }
438: name[len++] = *p;
439: p++;
440: }
441: name[len] = '\0';
442: *line = p;
443: return 1;
444: }
445:
446: /*
447: * parse a decimal integer
448: */
449: int
450: parse_unit(char **line, unsigned int *num)
451: {
452: char *p = *line;
453: unsigned int val;
454: int n;
455:
456: if (sscanf(p, "%u%n", &val, &n) != 1) {
457: fprintf(stderr, "number expected near '%s'\n", p);
458: return 0;
459: }
460: if (val >= 255) {
461: fprintf(stderr, "%d: too large\n", val);
462: return 0;
463: }
464: *num = val;
465: *line = p + n;
466: return 1;
467: }
468:
469: int
470: parse_val(char **line, float *num)
471: {
472: char *p = *line;
473: float val;
474: int n;
475:
476: if (sscanf(p, "%g%n", &val, &n) != 1) {
477: fprintf(stderr, "number expected near '%s'\n", p);
478: return 0;
479: }
480: if (val < 0 || val > 1) {
481: fprintf(stderr, "%g: expected number between 0 and 1\n", val);
482: return 0;
483: }
484: *num = val;
485: *line = p + n;
486: return 1;
487: }
488:
489: /*
490: * parse a sub-stream, eg. "spkr[7]"
491: */
492: int
493: parse_node(char **line, char *str, int *unit)
494: {
495: char *p = *line;
496:
497: if (!parse_name(&p, str))
498: return 0;
499: if (*p != '[') {
500: *unit = -1;
501: *line = p;
502: return 1;
503: }
504: p++;
505: if (!parse_unit(&p, unit))
506: return 0;
507: if (*p != ']') {
508: fprintf(stderr, "']' expected near '%s'\n", p);
509: return 0;
510: }
511: p++;
512: *line = p;
513: return 1;
514: }
515:
516: /*
517: * parse a decimal prefixed by the optional mode
518: */
519: int
520: parse_modeval(char **line, int *rmode, float *rval)
521: {
522: char *p = *line;
523: unsigned mode;
524:
525: switch (*p) {
526: case '+':
527: mode = MODE_ADD;
528: p++;
529: break;
530: case '-':
531: mode = MODE_SUB;
532: p++;
533: break;
534: case '!':
535: mode = MODE_TOGGLE;
536: p++;
537: break;
538: default:
539: mode = MODE_SET;
540: }
541: if (mode != MODE_TOGGLE) {
542: if (!parse_val(&p, rval))
543: return 0;
544: }
545: *line = p;
546: *rmode = mode;
547: return 1;
548: }
549:
550: /*
551: * dump the whole controls list, useful for debugging
552: */
553: void
554: dump(void)
555: {
556: struct info *i;
557:
558: for (i = infolist; i != NULL; i = i->next) {
559: printf("%03u:", i->ctladdr);
560: print_node(&i->desc.node0, 0);
561: printf(".%s", i->desc.func);
562: printf("=");
563: switch (i->desc.type) {
564: case SIOCTL_NUM:
565: case SIOCTL_SW:
566: printf("0..%d (%u)", i->desc.maxval, i->curval);
567: break;
568: case SIOCTL_VEC:
569: case SIOCTL_LIST:
570: print_node(&i->desc.node1, 0);
571: printf(":0..%d (%u)", i->desc.maxval, i->curval);
572: }
573: printf("\n");
574: }
575: }
576:
577: /*
578: * parse and execute a command ``<parameter>[=<value>]''
579: */
580: int
581: cmd(char *line)
582: {
583: char *pos, *group;
584: struct info *i, *e, *g;
585: char func[SIOCTL_NAMEMAX];
586: char astr[SIOCTL_NAMEMAX], vstr[SIOCTL_NAMEMAX];
587: int aunit, vunit;
588: unsigned npar = 0, nent = 0;
589: int comma, mode;
590: float val;
591:
592: pos = strrchr(line, '/');
593: if (pos != NULL) {
594: group = line;
595: pos[0] = 0;
596: pos++;
597: } else {
598: group = "";
599: pos = line;
600: }
601: if (!parse_node(&pos, astr, &aunit))
602: return 0;
603: if (*pos != '.') {
604: fprintf(stderr, "'.' expected near '%s'\n", pos);
605: return 0;
606: }
607: pos++;
608: if (!parse_name(&pos, func))
609: return 0;
610: for (g = infolist;; g = g->next) {
611: if (g == NULL) {
612: fprintf(stderr, "%s.%s: no such control\n", astr, func);
613: return 0;
614: }
615: if (strcmp(g->desc.group, group) == 0 &&
616: strcmp(g->desc.func, func) == 0 &&
617: strcmp(g->desc.node0.name, astr) == 0)
618: break;
619: }
620: g->mode = MODE_PRINT;
621: if (*pos != '=') {
622: if (*pos != '\0') {
623: fprintf(stderr, "junk at end of command\n");
624: return 0;
625: }
626: return 1;
627: }
628: pos++;
629: if (i_flag) {
630: printf("can't set values in info mode\n");
631: return 0;
632: }
633: npar = 0;
634: switch (g->desc.type) {
635: case SIOCTL_NUM:
636: case SIOCTL_SW:
637: if (!parse_modeval(&pos, &mode, &val))
638: return 0;
639: for (i = g; i != NULL; i = nextpar(i)) {
640: if (!matchpar(i, astr, aunit))
641: continue;
642: i->mode = mode;
643: i->newval = ftoi(val * i->desc.maxval);
644: npar++;
645: }
646: break;
647: case SIOCTL_VEC:
648: case SIOCTL_LIST:
649: for (i = g; i != NULL; i = nextpar(i)) {
650: if (!matchpar(i, astr, aunit))
651: continue;
652: for (e = i; e != NULL; e = nextent(e, 0)) {
653: e->newval = 0;
654: e->mode = MODE_SET;
655: }
656: npar++;
657: }
658: comma = 0;
659: for (;;) {
660: if (*pos == '\0')
661: break;
662: if (comma) {
663: if (*pos != ',')
664: break;
665: pos++;
666: }
667: if (!parse_node(&pos, vstr, &vunit))
668: return 0;
669: if (*pos == ':') {
670: pos++;
671: if (!parse_modeval(&pos, &mode, &val))
672: return 0;
673: } else {
674: val = 1.;
675: mode = MODE_SET;
676: }
677: nent = 0;
678: for (i = g; i != NULL; i = nextpar(i)) {
679: if (!matchpar(i, astr, aunit))
680: continue;
681: for (e = i; e != NULL; e = nextent(e, 0)) {
682: if (matchent(e, vstr, vunit)) {
683: e->newval = ftoi(val * e->desc.maxval);
684: e->mode = mode;
685: nent++;
686: }
687: }
688: }
689: if (nent == 0) {
690: /* XXX: use print_node()-like routine */
691: fprintf(stderr, "%s[%d]: invalid value\n", vstr, vunit);
692: print_par(g, 0, NULL);
693: exit(1);
694: }
695: comma = 1;
696: }
697: }
698: if (npar == 0) {
699: fprintf(stderr, "%s: invalid parameter\n", line);
700: exit(1);
701: }
702: if (*pos != '\0') {
703: printf("%s: junk at end of command\n", pos);
704: exit(1);
705: }
706: return 1;
707: }
708:
709: /*
710: * write the controls with the ``set'' flag on the device
711: */
712: void
713: commit(void)
714: {
715: struct info *i;
716: int val;
717:
718: for (i = infolist; i != NULL; i = i->next) {
719: val = 0xdeadbeef;
720: switch (i->mode) {
721: case MODE_IGNORE:
722: case MODE_PRINT:
723: continue;
724: case MODE_SET:
725: val = i->newval;
726: break;
727: case MODE_ADD:
728: val = i->curval + i->newval;
729: if (val > i->desc.maxval)
730: val = i->desc.maxval;
731: break;
732: case MODE_SUB:
733: val = i->curval - i->newval;
734: if (val < 0)
735: val = 0;
736: break;
737: case MODE_TOGGLE:
738: val = i->curval ? 0 : i->desc.maxval;
739: }
740: sioctl_setval(hdl, i->ctladdr, val);
741: i->curval = val;
742: }
743: }
744:
745: /*
746: * print all parameters
747: */
748: void
749: list(void)
750: {
751: struct info *p, *g;
752:
753: for (g = infolist; g != NULL; g = nextfunc(g)) {
754: if (g->mode == MODE_IGNORE)
755: continue;
756: if (i_flag) {
757: if (v_flag) {
758: for (p = g; p != NULL; p = nextpar(p))
759: print_par(p, 0, NULL);
760: } else
761: print_par(g, 1, NULL);
762: } else {
763: if (v_flag || !ismono(g)) {
764: for (p = g; p != NULL; p = nextpar(p))
765: print_par(p, 0, NULL);
766: } else
767: print_par(g, 1, NULL);
768: }
769: }
770: }
771:
772: /*
773: * register a new knob/button, called from the poll() loop. this may be
774: * called when label string changes, in which case we update the
775: * existing label widged rather than inserting a new one.
776: */
777: void
778: ondesc(void *arg, struct sioctl_desc *d, int curval)
779: {
780: struct info *i, **pi;
781: int cmp;
782:
783: if (d == NULL)
784: return;
785:
786: /*
787: * delete control
788: */
789: for (pi = &infolist; (i = *pi) != NULL; pi = &i->next) {
790: if (d->addr == i->desc.addr) {
791: if (m_flag)
792: print_par(i, 0, "deleted");
793: *pi = i->next;
794: free(i);
795: break;
796: }
797: }
798:
799: if (d->type == SIOCTL_NONE)
800: return;
801:
802: /*
803: * find the right position to insert the new widget
804: */
805: for (pi = &infolist; (i = *pi) != NULL; pi = &i->next) {
806: cmp = cmpdesc(d, &i->desc);
807: if (cmp == 0) {
808: fprintf(stderr, "fatal: duplicate control:\n");
809: print_par(i, 0, "duplicate");
810: exit(1);
811: }
812: if (cmp < 0)
813: break;
814: }
815: i = malloc(sizeof(struct info));
816: if (i == NULL) {
817: perror("malloc");
818: exit(1);
819: }
820: i->desc = *d;
821: i->ctladdr = d->addr;
822: i->curval = i->newval = curval;
823: i->mode = MODE_IGNORE;
824: i->next = *pi;
825: *pi = i;
826: if (m_flag)
827: print_par(i, 0, "added");
828: }
829:
830: /*
831: * update a knob/button state, called from the poll() loop
832: */
833: void
834: onctl(void *arg, unsigned addr, unsigned val)
835: {
836: struct info *i;
837:
838: for (i = infolist; i != NULL; i = i->next) {
839: if (i->ctladdr != addr)
840: continue;
841: i->curval = val;
842: if (m_flag)
843: print_par(i, 0, "changed");
844: }
845: }
846:
847: int
848: main(int argc, char **argv)
849: {
850: char *devname = SIO_DEVANY;
851: int i, c, d_flag = 0;
852: struct info *g;
853: struct pollfd *pfds;
854: int nfds, revents;
855:
856: while ((c = getopt(argc, argv, "df:imv")) != -1) {
857: switch (c) {
858: case 'd':
859: d_flag = 1;
860: break;
861: case 'f':
862: devname = optarg;
863: break;
864: case 'i':
865: i_flag = 1;
866: break;
867: case 'm':
868: m_flag = 1;
869: break;
870: case 'v':
871: v_flag++;
872: break;
873: default:
874: fprintf(stderr, "usage: sndioctl "
1.2 ! ratchov 875: "[-dimv] [-f device] [command ...]\n");
1.1 ratchov 876: exit(1);
877: }
878: }
879: argc -= optind;
880: argv += optind;
881:
882: hdl = sioctl_open(devname, SIOCTL_READ | SIOCTL_WRITE, 0);
883: if (hdl == NULL) {
884: fprintf(stderr, "%s: can't open control device\n", devname);
885: exit(1);
886: }
887: if (!sioctl_ondesc(hdl, ondesc, NULL)) {
888: fprintf(stderr, "%s: can't get device description\n", devname);
889: exit(1);
890: }
891: sioctl_onval(hdl, onctl, NULL);
892:
893: if (d_flag) {
894: if (argc > 0) {
895: fprintf(stderr,
896: "commands are not allowed with -d option\n");
897: exit(1);
898: }
899: dump();
900: } else {
901: if (argc == 0) {
902: for (g = infolist; g != NULL; g = nextfunc(g))
903: g->mode = MODE_PRINT;
904: } else {
905: for (i = 0; i < argc; i++) {
906: if (!cmd(argv[i]))
907: return 1;
908: }
909: }
910: commit();
911: list();
912: }
913: if (m_flag) {
914: pfds = malloc(sizeof(struct pollfd) * sioctl_nfds(hdl));
915: if (pfds == NULL) {
916: perror("malloc");
917: exit(1);
918: }
919: for (;;) {
920: nfds = sioctl_pollfd(hdl, pfds, POLLIN);
921: if (nfds == 0)
922: break;
923: while (poll(pfds, nfds, -1) < 0) {
924: if (errno != EINTR) {
925: perror("poll");
926: exit(1);
927: }
928: }
929: revents = sioctl_revents(hdl, pfds);
930: if (revents & POLLHUP) {
931: fprintf(stderr, "disconnected\n");
932: break;
933: }
934: }
935: free(pfds);
936: }
937: sioctl_close(hdl);
938: return 0;
939: }