• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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