Skip to content

Commit

Permalink
iio_attr: Fix getopt() handling
Browse files Browse the repository at this point in the history
iio_attr currently assumes that the argument for an option that is parsed
by getopt_long() is in the argv[] following the option and then the
combination of option and argument always consumes two argv[] entries.

This is not necessarily true though. getopt_long() accepts option and
argument in the same argv[] entry. For short options the argument can
directly follow the option character and for long options the argument can
follow in the same argv[] entry separated by a '=' character.

E.g. both -u ip:192.168.1.1 and -uip:192.168.1.1 as well as --uri
192.168.1.1 and --uri=192.168.1.1 are equivalent and all valid.

As a result of this iio_attr will show undefined behavior when option and
argument are passed in the same argv[] entry (E.g. crash with a
segmentation fault).

To address this properly use the optarg and optind variables that are
provided by the getopt() interface. optarg points to the start of the
argument for the current option and optind will point to the first non
option argv[] entry after all options have been scanned.

Signed-off-by: Lars-Peter Clausen <[email protected]>
  • Loading branch information
larsclausen authored and commodo committed Feb 28, 2018
1 parent 989db5e commit faa6341
Showing 1 changed file with 38 additions and 49 deletions.
87 changes: 38 additions & 49 deletions tests/iio_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,9 @@ static void usage(void)
int main(int argc, char **argv)
{
struct iio_context *ctx;
int c, option_index = 0, arg_index = 0, uri_index = 0,
device_index = 0, channel_index = 0, attr_index = 0;
int c, option_index = 0;
int device_index = 0, channel_index = 0, attr_index = 0;
const char *arg_uri = NULL;
enum backend backend = LOCAL;
bool detect_context = false, search_device = false, ignore_case = false,
search_channel = false, search_buffer = false, search_debug = false,
Expand All @@ -394,57 +395,45 @@ int main(int argc, char **argv)
return EXIT_SUCCESS;
/* context connection */
case 'a':
arg_index += 1;
detect_context = true;
break;
case 'u':
backend = AUTO;
arg_index += 2;
uri_index = arg_index;
arg_uri = optarg;
break;
/* Attribute type
* 'd'evice, 'c'hannel, 'C'ontext, 'B'uffer or 'D'ebug
*/
case 'd':
arg_index += 1;
search_device = true;
break;
case 'c':
arg_index += 1;
search_channel = true;
break;
case 'B':
arg_index +=1;
search_buffer = true;
break;
case 'D':
arg_index +=1;
search_debug = true;
break;
case 'C':
arg_index +=1;
search_context = true;
break;
/* Channel qualifiers */
case 'i':
arg_index += 1;
input_only = true;
break;
case 'o':
arg_index += 1;
output_only = true;
break;
case 's':
arg_index += 1;
scan_only = true;
break;
/* options */
case 'I':
arg_index += 1;
ignore_case = true;
break;
case 'q':
arg_index += 1;
quiet = true;
break;
case '?':
Expand All @@ -470,59 +459,59 @@ int main(int argc, char **argv)

if (search_context) {
/* -C [IIO_attribute] */
if (argc >= arg_index + 2)
attr_index = arg_index + 1;
if (argc >= arg_index + 3) {
if (argc >= optind + 1)
attr_index = optind;
if (argc >= optind + 2) {
fprintf(stderr, "Too many options for searching for context attributes\n");
return EXIT_FAILURE;
}
} else if (search_device) {
/* -d [device] [attr] [value] */
if (argc >= arg_index + 2)
device_index = arg_index + 1;
if (argc >= arg_index + 3)
attr_index = arg_index + 2;
if (argc >= arg_index + 4)
wbuf = argv[arg_index + 3];
if (argc >= arg_index + 5) {
if (argc >= optind + 1)
device_index = optind;
if (argc >= optind + 2)
attr_index = optind + 1;
if (argc >= optind + 3)
wbuf = argv[optind + 2];
if (argc >= optind + 4) {
fprintf(stderr, "Too many options for searching for device attributes\n");
return EXIT_FAILURE;
}
} else if (search_channel) {
/* -c [device] [channel] [attr] [value] */
if (argc >= arg_index + 2)
device_index = arg_index + 1;
if (argc >= arg_index + 3)
channel_index = arg_index + 2;
if (argc >= arg_index + 4)
attr_index = arg_index + 3;
if (argc >= arg_index + 5)
wbuf = argv[arg_index + 4];
if (argc >= arg_index + 6) {
if (argc >= optind + 1)
device_index = optind;
if (argc >= optind + 2)
channel_index = optind + 1;
if (argc >= optind + 3)
attr_index = optind + 2;
if (argc >= optind + 4)
wbuf = argv[optind + 3];
if (argc >= optind + 5) {
fprintf(stderr, "Too many options for searching for channel attributes\n");
return EXIT_FAILURE;
}
} else if (search_buffer) {
/* -B [device] [attribute] [value] */
if (argc >= arg_index + 2)
device_index = arg_index + 1;
if (argc >= arg_index + 3)
attr_index = arg_index + 2;
if (argc >= arg_index + 4)
wbuf = argv[arg_index + 3];
if (argc >= arg_index + 5) {
if (argc >= optind + 1)
device_index = optind;
if (argc >= optind + 2)
attr_index = optind + 1;
if (argc >= optind + 3)
wbuf = argv[optind + 2];
if (argc >= optind + 4) {
fprintf(stderr, "Too many options for searching for buffer attributes\n");
return EXIT_FAILURE;
}
} else if (search_debug) {
/* -D [device] [attribute] [value] */
if (argc >= arg_index + 2)
device_index = arg_index + 1;
if (argc >= arg_index + 3)
attr_index = arg_index + 2;
if (argc >= arg_index + 4)
wbuf = argv[arg_index + 3];
if (argc >= arg_index + 5) {
if (argc >= optind + 1)
device_index = optind;
if (argc >= optind + 2)
attr_index = optind + 1;
if (argc >= optind + 3)
wbuf = argv[optind + 2];
if (argc >= optind + 4) {
fprintf(stderr, "Too many options for searching for device attributes\n");
return EXIT_FAILURE;
}
Expand Down Expand Up @@ -552,7 +541,7 @@ int main(int argc, char **argv)
if (detect_context)
ctx = autodetect_context();
else if (backend == AUTO)
ctx = iio_create_context_from_uri(argv[uri_index]);
ctx = iio_create_context_from_uri(arg_uri);
else
ctx = iio_create_default_context();

Expand Down

0 comments on commit faa6341

Please sign in to comment.