1 /*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
4 * Copyright (C) 2014, 2017 Analog Devices, Inc.
5 * Author: Paul Cercueil <paul.cercueil@analog.com>
6 * Robin Getz <robin.getz@analog.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * */
19
20 #include <errno.h>
21 #include <getopt.h>
22 #include <iio.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <sys/types.h>
28
29 #define MY_NAME "iio_attr"
30
31 #ifdef _WIN32
32 #define snprintf sprintf_s
33 #else
34 #define _strdup strdup
35 #endif
36
37 enum backend {
38 LOCAL,
39 XML,
40 AUTO
41 };
42
str_match(const char * haystack,char * needle,bool ignore)43 static bool str_match(const char * haystack, char * needle, bool ignore)
44 {
45 bool ret = false;
46 int i;
47 char *ncpy, *hcpy, *idx, first, last;
48
49 if (!haystack || !needle)
50 return false;
51
52 if (!strlen(haystack) || !strlen(needle))
53 return false;
54
55 /* '.' means match any */
56 if (!strcmp(".", needle) || !strcmp("*", needle))
57 return true;
58
59 ncpy = _strdup(needle);
60 hcpy = _strdup(haystack);
61
62 if (!ncpy || !hcpy)
63 goto eek;
64
65 if (ignore) {
66 for (i = 0; hcpy[i]; i++)
67 hcpy[i] = tolower(hcpy[i]);
68 for (i = 0; ncpy[i]; i++)
69 ncpy[i] = tolower(ncpy[i]);
70 }
71
72 first = ncpy[0];
73 last = ncpy[strlen(ncpy) - 1];
74
75 if (first != '*' && last == '*') {
76 /* 'key*' */
77 ret = !strncmp(hcpy, ncpy, strlen(ncpy) - 1);
78 } else if ((first == '*') && (last == '*')) {
79 /* '*key*' */
80 ncpy[strlen(ncpy) - 1] = 0;
81 ret = strstr(hcpy, &ncpy[1]);
82 } else if ((first == '*') && (last != '*')) {
83 /* '*key' */
84 idx = strstr(hcpy, &ncpy[1]);
85 if ((idx + strlen(&ncpy[1])) == (hcpy + strlen(hcpy)))
86 ret = true;
87 } else {
88 /* 'key' */
89 ret = !strcmp(hcpy, ncpy);
90 }
91
92 eek:
93 free(ncpy);
94 free(hcpy);
95
96 return ret;
97 }
98
autodetect_context(void)99 static struct iio_context * autodetect_context(void)
100 {
101 struct iio_scan_context *scan_ctx;
102 struct iio_context_info **info;
103 struct iio_context *ctx = NULL;
104 unsigned int i;
105 ssize_t ret;
106
107 scan_ctx = iio_create_scan_context(NULL, 0);
108 if (!scan_ctx) {
109 fprintf(stderr, "Unable to create scan context\n");
110 return NULL;
111 }
112
113 ret = iio_scan_context_get_info_list(scan_ctx, &info);
114 if (ret < 0) {
115 char err_str[1024];
116 iio_strerror(-ret, err_str, sizeof(err_str));
117 fprintf(stderr, "Scanning for IIO contexts failed: %s\n", err_str);
118 goto err_free_ctx;
119 }
120
121 if (ret == 0) {
122 printf("No IIO context found.\n");
123 goto err_free_info_list;
124 }
125 if (ret == 1) {
126 printf("Using auto-detected IIO context at URI \"%s\"\n",
127 iio_context_info_get_uri(info[0]));
128 ctx = iio_create_context_from_uri(iio_context_info_get_uri(info[0]));
129 } else {
130 fprintf(stderr, "Multiple contexts found. Please select one using --uri:\n");
131 for (i = 0; i < (size_t) ret; i++) {
132 fprintf(stderr, "\t%d: %s [%s]\n",
133 i, iio_context_info_get_description(info[i]),
134 iio_context_info_get_uri(info[i]));
135 }
136 }
137
138 err_free_info_list:
139 iio_context_info_list_free(info);
140 err_free_ctx:
141 iio_scan_context_destroy(scan_ctx);
142
143 return ctx;
144 }
145
146
dump_device_attributes(const struct iio_device * dev,const char * attr,const char * wbuf,bool quiet)147 static void dump_device_attributes(const struct iio_device *dev,
148 const char *attr, const char *wbuf, bool quiet)
149 {
150 ssize_t ret;
151 char buf[1024];
152
153 if (!wbuf || !quiet) {
154 if (!quiet)
155 printf("dev '%s', attr '%s', value :",
156 iio_device_get_name(dev), attr);
157 ret = iio_device_attr_read(dev, attr, buf, sizeof(buf));
158 if (ret > 0) {
159 if (quiet)
160 printf("%s\n", buf);
161 else
162 printf("'%s'\n", buf);
163 } else {
164 iio_strerror(-ret, buf, sizeof(buf));
165 printf("ERROR: %s (%li)\n", buf, (long)ret);
166 }
167 }
168 if (wbuf) {
169 ret = iio_device_attr_write(dev, attr, wbuf);
170 if (ret > 0) {
171 if (!quiet)
172 printf("wrote %li bytes to %s\n", (long)ret, attr);
173 } else {
174 iio_strerror(-ret, buf, sizeof(buf));
175 printf("ERROR: %s (%li) while writing '%s' with '%s'\n",
176 buf, (long)ret, attr, wbuf);
177 }
178 dump_device_attributes(dev, attr, NULL, quiet);
179 }
180 }
181
dump_buffer_attributes(const struct iio_device * dev,const char * attr,const char * wbuf,bool quiet)182 static void dump_buffer_attributes(const struct iio_device *dev,
183 const char *attr, const char *wbuf, bool quiet)
184 {
185 ssize_t ret;
186 char buf[1024];
187
188 if (!wbuf || !quiet) {
189 ret = iio_device_buffer_attr_read(dev, attr, buf, sizeof(buf));
190
191 if (!quiet)
192 printf("dev '%s', buffer attr '%s', value :",
193 iio_device_get_name(dev), attr);
194
195 if (ret > 0) {
196 if (quiet)
197 printf("%s\n", buf);
198 else
199 printf("'%s'\n", buf);
200 } else {
201 iio_strerror(-ret, buf, sizeof(buf));
202 printf("ERROR: %s (%li)\n", buf, (long)ret);
203 }
204 }
205
206 if (wbuf) {
207 ret = iio_device_buffer_attr_write(dev, attr, wbuf);
208 if (ret > 0) {
209 if (!quiet)
210 printf("wrote %li bytes to %s\n", (long)ret, attr);
211 } else {
212 iio_strerror(-ret, buf, sizeof(buf));
213 printf("ERROR: %s (%li) while writing '%s' with '%s'\n",
214 buf, (long)ret, attr, wbuf);
215 }
216 dump_buffer_attributes(dev, attr, NULL, quiet);
217 }
218 }
219
dump_debug_attributes(const struct iio_device * dev,const char * attr,const char * wbuf,bool quiet)220 static void dump_debug_attributes(const struct iio_device *dev,
221 const char *attr, const char *wbuf, bool quiet)
222 {
223 ssize_t ret;
224 char buf[1024];
225
226 if (!wbuf || !quiet) {
227 ret = iio_device_debug_attr_read(dev, attr, buf, sizeof(buf));
228
229 if (!quiet)
230 printf("dev '%s', debug attr '%s', value :",
231 iio_device_get_name(dev), attr);
232
233 if (ret > 0) {
234 if (quiet)
235 printf("%s\n", buf);
236 else
237 printf("'%s'\n", buf);
238 } else {
239 iio_strerror(-ret, buf, sizeof(buf));
240 printf("ERROR: %s (%li)\n", buf, (long)ret);
241 }
242 }
243
244 if (wbuf) {
245 ret = iio_device_debug_attr_write(dev, attr, wbuf);
246 if (ret > 0) {
247 if (!quiet)
248 printf("wrote %li bytes to %s\n", (long)ret, attr);
249 } else {
250 iio_strerror(-ret, buf, sizeof(buf));
251 printf("ERROR: %s (%li) while writing '%s' with '%s'\n",
252 buf, (long)ret, attr, wbuf);
253 }
254 dump_debug_attributes(dev, attr, NULL, quiet);
255 }
256 }
257
dump_channel_attributes(const struct iio_device * dev,struct iio_channel * ch,const char * attr,const char * wbuf,bool quiet)258 static void dump_channel_attributes(const struct iio_device *dev,
259 struct iio_channel *ch, const char *attr, const char *wbuf, bool quiet)
260 {
261 ssize_t ret;
262 char buf[1024];
263 const char *type_name;
264
265 if (!wbuf || !quiet) {
266 if (iio_channel_is_output(ch))
267 type_name = "output";
268 else
269 type_name = "input";
270
271 ret = iio_channel_attr_read(ch, attr, buf, sizeof(buf));
272 if (!quiet)
273 printf("dev '%s', channel '%s' (%s), ",
274 iio_device_get_name(dev),
275 iio_channel_get_id(ch),
276 type_name);
277 if (iio_channel_get_name(ch) && !quiet)
278 printf("id '%s', ", iio_channel_get_name(ch));
279
280 if (!quiet)
281 printf("attr '%s', ", attr);
282
283 if (ret > 0) {
284 if (quiet)
285 printf("%s\n", buf);
286 else
287 printf("value '%s'\n", buf);
288 } else {
289 iio_strerror(-ret, buf, sizeof(buf));
290 printf("ERROR: %s (%li)\n", buf, (long)ret);
291 }
292 }
293 if (wbuf) {
294 ret = iio_channel_attr_write(ch, attr, wbuf);
295 if (ret > 0) {
296 if (!quiet)
297 printf("wrote %li bytes to %s\n", (long)ret, attr);
298 } else {
299 iio_strerror(-ret, buf, sizeof(buf));
300 printf("error %s (%li) while writing '%s' with '%s'\n",
301 buf, (long)ret, attr, wbuf);
302 }
303 dump_channel_attributes(dev, ch, attr, NULL, quiet);
304 }
305 }
306
307 static const struct option options[] = {
308 /* help */
309 {"help", no_argument, 0, 'h'},
310 {"ignore-case", no_argument, 0, 'I'},
311 {"quiet", no_argument, 0, 'q'},
312 /* context connection */
313 {"auto", no_argument, 0, 'a'},
314 {"uri", required_argument, 0, 'u'},
315 /* Channel qualifiers */
316 {"input-channel", no_argument, 0, 'i'},
317 {"output-channel", no_argument, 0, 'o'},
318 {"scan-channel", no_argument, 0, 's'},
319 /* Attribute type */
320 {"device-attr", no_argument, 0, 'd'},
321 {"channel-attr", no_argument, 0, 'c'},
322 {"context-attr", no_argument, 0, 'C'},
323 {"buffer-attr", no_argument, 0, 'B'},
324 {"debug-attr", no_argument, 0, 'D'},
325 {0, 0, 0, 0},
326 };
327
328 static const char *options_descriptions[] = {
329 /* help */
330 "Show this help and quit.",
331 "Ignore case distinctions.",
332 "Return result only.",
333 /* context connection */
334 "Use the first context found.",
335 "Use the context at the provided URI.",
336 /* Channel qualifiers */
337 "Filter Input Channels only.",
338 "Filter Output Channels only.",
339 "Filter Scan Channels only.",
340 /* attribute type */
341 "Read/Write device attributes",
342 "Read/Write channel attributes.",
343 "Read IIO context attributes.",
344 "Read/Write buffer attributes.",
345 "Read/Write debug attributes.",
346 };
347
usage(void)348 static void usage(void)
349 {
350 unsigned int i, j = 0, k;
351
352 printf("Usage:\n\t" MY_NAME " [OPTION]...\t-d [device] [attr] [value]\n"
353 "\t\t\t\t-c [device] [channel] [attr] [value]\n"
354 "\t\t\t\t-B [device] [attr] [value]\n"
355 "\t\t\t\t-D [device] [attr] [value]\n"
356 "\t\t\t\t-C [attr]\nOptions:\n");
357 for (i = 0; options[i].name; i++) {
358 k = strlen(options[i].name);
359 if (k > j)
360 j = k;
361 }
362 j++;
363 for (i = 0; options[i].name; i++) {
364 printf("\t-%c, --%s%*c: %s\n",
365 options[i].val, options[i].name,
366 j - (int)strlen(options[i].name), ' ',
367 options_descriptions[i]);
368 if (i == 3)
369 printf("Optional qualifiers:\n");
370 if (i == 6)
371 printf("Attribute types:\n");
372 }
373 }
374
main(int argc,char ** argv)375 int main(int argc, char **argv)
376 {
377 struct iio_context *ctx;
378 int c, option_index = 0;
379 int device_index = 0, channel_index = 0, attr_index = 0;
380 const char *arg_uri = NULL;
381 enum backend backend = LOCAL;
382 bool detect_context = false, search_device = false, ignore_case = false,
383 search_channel = false, search_buffer = false, search_debug = false,
384 search_context = false, input_only = false, output_only = false,
385 scan_only = false, quiet = false;
386 unsigned int i;
387 char *wbuf = NULL;
388
389 while ((c = getopt_long(argc, argv, "+hau:CdcBDiosIq",
390 options, &option_index)) != -1) {
391 switch (c) {
392 /* help */
393 case 'h':
394 usage();
395 return EXIT_SUCCESS;
396 /* context connection */
397 case 'a':
398 detect_context = true;
399 break;
400 case 'u':
401 backend = AUTO;
402 arg_uri = optarg;
403 break;
404 /* Attribute type
405 * 'd'evice, 'c'hannel, 'C'ontext, 'B'uffer or 'D'ebug
406 */
407 case 'd':
408 search_device = true;
409 break;
410 case 'c':
411 search_channel = true;
412 break;
413 case 'B':
414 search_buffer = true;
415 break;
416 case 'D':
417 search_debug = true;
418 break;
419 case 'C':
420 search_context = true;
421 break;
422 /* Channel qualifiers */
423 case 'i':
424 input_only = true;
425 break;
426 case 'o':
427 output_only = true;
428 break;
429 case 's':
430 scan_only = true;
431 break;
432 /* options */
433 case 'I':
434 ignore_case = true;
435 break;
436 case 'q':
437 quiet = true;
438 break;
439 case '?':
440 printf("Unknown argument '%c'\n", c);
441 return EXIT_FAILURE;
442 }
443 }
444
445 if ((search_device + search_channel + search_context + search_debug + search_buffer) >= 2 ) {
446 fprintf(stderr, "The options -d, -c, -C, -B, and -D are exclusive"
447 " (can use only one).\n");
448 return EXIT_FAILURE;
449 }
450
451 if (!(search_device + search_channel + search_context + search_debug + search_buffer)) {
452 if (argc == 1) {
453 usage();
454 return EXIT_SUCCESS;
455 }
456 fprintf(stderr, "must specify one of -d, -c, -C, -B or -D.\n");
457 return EXIT_FAILURE;
458 }
459
460 if (search_context) {
461 /* -C [IIO_attribute] */
462 if (argc >= optind + 1)
463 attr_index = optind;
464 if (argc >= optind + 2) {
465 fprintf(stderr, "Too many options for searching for context attributes\n");
466 return EXIT_FAILURE;
467 }
468 } else if (search_device) {
469 /* -d [device] [attr] [value] */
470 if (argc >= optind + 1)
471 device_index = optind;
472 if (argc >= optind + 2)
473 attr_index = optind + 1;
474 if (argc >= optind + 3)
475 wbuf = argv[optind + 2];
476 if (argc >= optind + 4) {
477 fprintf(stderr, "Too many options for searching for device attributes\n");
478 return EXIT_FAILURE;
479 }
480 } else if (search_channel) {
481 /* -c [device] [channel] [attr] [value] */
482 if (argc >= optind + 1)
483 device_index = optind;
484 if (argc >= optind + 2)
485 channel_index = optind + 1;
486 if (argc >= optind + 3)
487 attr_index = optind + 2;
488 if (argc >= optind + 4)
489 wbuf = argv[optind + 3];
490 if (argc >= optind + 5) {
491 fprintf(stderr, "Too many options for searching for channel attributes\n");
492 return EXIT_FAILURE;
493 }
494 } else if (search_buffer) {
495 /* -B [device] [attribute] [value] */
496 if (argc >= optind + 1)
497 device_index = optind;
498 if (argc >= optind + 2)
499 attr_index = optind + 1;
500 if (argc >= optind + 3)
501 wbuf = argv[optind + 2];
502 if (argc >= optind + 4) {
503 fprintf(stderr, "Too many options for searching for buffer attributes\n");
504 return EXIT_FAILURE;
505 }
506 } else if (search_debug) {
507 /* -D [device] [attribute] [value] */
508 if (argc >= optind + 1)
509 device_index = optind;
510 if (argc >= optind + 2)
511 attr_index = optind + 1;
512 if (argc >= optind + 3)
513 wbuf = argv[optind + 2];
514 if (argc >= optind + 4) {
515 fprintf(stderr, "Too many options for searching for device attributes\n");
516 return EXIT_FAILURE;
517 }
518 } else {
519 fprintf(stderr, "error in application\n");
520 return EXIT_FAILURE;
521 }
522
523 if (device_index && !argv[device_index])
524 return EXIT_FAILURE;
525 if (channel_index && !argv[channel_index])
526 return EXIT_FAILURE;
527 if (attr_index && !argv[attr_index])
528 return EXIT_FAILURE;
529 if (wbuf && !wbuf)
530 return EXIT_FAILURE;
531 if (wbuf && ((device_index && (!strcmp(".", argv[device_index]) ||
532 strchr(argv[device_index], '*'))) ||
533 (channel_index && (!strcmp(".", argv[channel_index]) ||
534 strchr(argv[channel_index], '*'))) ||
535 (attr_index && (!strcmp(".", argv[attr_index]) ||
536 strchr(argv[attr_index], '*'))))) {
537 printf("can't write value with wildcard match\n");
538 return EXIT_FAILURE;
539 }
540
541 if (detect_context)
542 ctx = autodetect_context();
543 else if (backend == AUTO)
544 ctx = iio_create_context_from_uri(arg_uri);
545 else
546 ctx = iio_create_default_context();
547
548 if (!ctx) {
549 if (!detect_context) {
550 char buf[1024];
551
552 iio_strerror(errno, buf, sizeof(buf));
553 fprintf(stderr, "Unable to create IIO context: %s\n",
554 buf);
555 }
556
557 return EXIT_FAILURE;
558 }
559
560 if (search_context) {
561 unsigned int nb_ctx_attrs = iio_context_get_attrs_count(ctx);
562 if (!attr_index && nb_ctx_attrs > 0)
563 printf("IIO context with %u attributes:\n", nb_ctx_attrs);
564
565 for (i = 0; i < nb_ctx_attrs; i++) {
566 const char *key, *value;
567
568 iio_context_get_attr(ctx, i, &key, &value);
569 if (!attr_index || str_match(key, argv[attr_index], ignore_case)) {
570 printf("%s: %s\n", key, value);
571 }
572 }
573 }
574
575 if (search_device || search_channel || search_buffer || search_debug) {
576 unsigned int nb_devices = iio_context_get_devices_count(ctx);
577
578 if (!device_index)
579 printf("IIO context has %u devices:\n", nb_devices);
580
581 for (i = 0; i < nb_devices; i++) {
582 const struct iio_device *dev = iio_context_get_device(ctx, i);
583 const char *name = iio_device_get_name(dev);
584 unsigned int nb_attrs, nb_channels, j;
585
586
587 if (device_index && !str_match(name, argv[device_index], ignore_case))
588 continue;
589
590 if ((search_device && !device_index) || (search_channel && !device_index) ||
591 (search_buffer && !device_index) || (search_debug && !device_index)) {
592 printf("\t%s:", iio_device_get_id(dev));
593 if (name)
594 printf(" %s", name);
595 printf(", ");
596 }
597
598 if (search_channel && !device_index)
599 printf("found %u channels\n", iio_device_get_channels_count(dev));
600
601 nb_channels = iio_device_get_channels_count(dev);
602 for (j = 0; j < nb_channels; j++) {
603 struct iio_channel *ch;
604 const char *type_name;
605 unsigned int k, nb_attrs;
606
607 if (!search_channel || !device_index)
608 continue;
609
610 ch = iio_device_get_channel(dev, j);
611
612 if (input_only && iio_channel_is_output(ch))
613 continue;
614 if (output_only && !iio_channel_is_output(ch))
615 continue;
616 if (scan_only && !iio_channel_is_scan_element(ch))
617 continue;
618
619 if (iio_channel_is_output(ch))
620 type_name = "output";
621 else
622 type_name = "input";
623
624 name = iio_channel_get_name(ch);
625 if (channel_index &&
626 !str_match(iio_channel_get_id(ch),
627 argv[channel_index], ignore_case) &&
628 (!name || (name &&
629 !str_match( name,argv[channel_index], ignore_case))))
630 continue;
631
632 if ((!scan_only && !channel_index) ||
633 ( scan_only && iio_channel_is_scan_element(ch))) {
634 printf("dev '%s', channel '%s'",
635 iio_device_get_name(dev),
636 iio_channel_get_id(ch));
637
638 if (name)
639 printf(", id '%s'", name);
640
641 printf(" (%s", type_name);
642
643 if (iio_channel_is_scan_element(ch)) {
644 const struct iio_data_format *format =
645 iio_channel_get_data_format(ch);
646 char sign = format->is_signed ? 's' : 'u';
647 char repeat[12] = "";
648
649 if (format->is_fully_defined)
650 sign += 'A' - 'a';
651
652 if (format->repeat > 1)
653 snprintf(repeat, sizeof(repeat), "X%u",
654 format->repeat);
655 printf(", index: %lu, format: %ce:%c%u/%u%s>>%u)",
656 iio_channel_get_index(ch),
657 format->is_be ? 'b' : 'l',
658 sign, format->bits,
659 format->length, repeat,
660 format->shift);
661 if (scan_only)
662 printf("\n");
663 else
664 printf(", ");
665 } else {
666 printf("), ");
667 }
668
669 }
670
671 nb_attrs = iio_channel_get_attrs_count(ch);
672 if (!channel_index)
673 printf("found %u channel-specific attributes\n",
674 nb_attrs);
675
676 if (!nb_attrs || !channel_index)
677 continue;
678
679 for (k = 0; k < nb_attrs; k++) {
680 const char *attr =
681 iio_channel_get_attr(ch, k);
682
683 if (attr_index &&
684 !str_match(attr, argv[attr_index],
685 ignore_case))
686 continue;
687
688 dump_channel_attributes(dev, ch, attr, wbuf,
689 attr_index ? quiet : false);
690 }
691 }
692
693 nb_attrs = iio_device_get_attrs_count(dev);
694 if (search_device && !device_index)
695 printf("found %u device attributes\n", nb_attrs);
696
697 if (search_device && device_index && nb_attrs) {
698 unsigned int j;
699 for (j = 0; j < nb_attrs; j++) {
700 const char *attr = iio_device_get_attr(dev, j);
701
702 if (attr_index &&
703 !str_match(attr, argv[attr_index], ignore_case))
704 continue;
705
706 dump_device_attributes(dev, attr, wbuf,
707 attr_index ? quiet : false);
708 }
709 }
710
711 nb_attrs = iio_device_get_buffer_attrs_count(dev);
712
713 if (search_buffer && !device_index)
714 printf("found %u buffer attributes\n", nb_attrs);
715
716 if (search_buffer && device_index && nb_attrs) {
717 unsigned int j;
718
719 for (j = 0; j < nb_attrs; j++) {
720 const char *attr = iio_device_get_buffer_attr(dev, j);
721
722 if ((attr_index && str_match(attr, argv[attr_index],
723 ignore_case)) || !attr_index)
724 dump_buffer_attributes(dev, attr, wbuf,
725 attr_index ? quiet : false);
726 }
727
728 }
729
730 nb_attrs = iio_device_get_debug_attrs_count(dev);
731
732 if (search_debug && !device_index)
733 printf("found %u debug attributes\n", nb_attrs);
734
735 if (search_debug && device_index && nb_attrs) {
736 unsigned int j;
737
738 for (j = 0; j < nb_attrs; j++) {
739 const char *attr = iio_device_get_debug_attr(dev, j);
740
741 if ((attr_index && str_match(attr, argv[attr_index],
742 ignore_case)) || !attr_index)
743 dump_debug_attributes(dev, attr, wbuf,
744 attr_index ? quiet : false);
745 }
746
747 }
748 }
749
750 }
751
752 iio_context_destroy(ctx);
753 return EXIT_SUCCESS;
754 }
755