blob: 093e467de1c9a3ccc869f72061b0b962e91f687d [file] [log] [blame]
Chris Fries4868b072014-10-06 11:24:54 -05001/*
2 * Copyright (c) 2008, The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google, Inc. nor the names of its contributors
15 * may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <errno.h>
33#include <error.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080034#include <fcntl.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -080035#include <getopt.h>
Chris Fries4868b072014-10-06 11:24:54 -050036#include <stdio.h>
37#include <stdint.h>
38#include <stdlib.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080039#include <string.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -080040#include <sys/ioctl.h>
Elliott Hughes0badbd62014-12-29 12:24:25 -080041#include <unistd.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080042
Chris Fries4868b072014-10-06 11:24:54 -050043static void usage() {
44 fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
45 " -l <length> Length of io buffer\n"
46 " -a <argsize> Size of each argument (1-8)\n"
47 " -r Open device in read only mode\n"
48 " -d Direct argument (no iobuffer)\n"
49 " -h Print help\n", getprogname());
50 exit(1);
51}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080052
Chris Fries4868b072014-10-06 11:24:54 -050053static int xstrtoi(const char* s, const char* what) {
54 char* endp;
55 errno = 0;
56 long result = strtol(s, &endp, 0);
57 if (errno != 0 || *endp != '\0') {
58 error(1, errno, "couldn't parse %s '%s'", what, s);
59 }
60 if (result > INT_MAX || result < INT_MIN) {
61 error(1, errno, "%s '%s' out of range", what, s);
62 }
63 return result;
64}
65
66int ioctl_main(int argc, char* argv[]) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080067 int read_only = 0;
68 int length = -1;
69 int arg_size = 4;
70 int direct_arg = 0;
Chris Fries4868b072014-10-06 11:24:54 -050071
Mark Salyzynaa907762014-05-08 09:31:43 -070072 void *ioctl_args = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080073 uint8_t *ioctl_argp;
Mark Salyzynaa907762014-05-08 09:31:43 -070074 uint8_t *ioctl_argp_save = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080075 int rem;
76
Chris Fries4868b072014-10-06 11:24:54 -050077 int c;
78 while ((c = getopt(argc, argv, "rdl:a:h")) != -1) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080079 switch (c) {
80 case 'r':
81 read_only = 1;
82 break;
83 case 'd':
84 direct_arg = 1;
85 break;
86 case 'l':
Chris Fries4868b072014-10-06 11:24:54 -050087 length = xstrtoi(optarg, "length");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080088 break;
89 case 'a':
Chris Fries4868b072014-10-06 11:24:54 -050090 arg_size = xstrtoi(optarg, "argument size");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080091 break;
92 case 'h':
Chris Fries4868b072014-10-06 11:24:54 -050093 usage();
94 break;
95 default:
96 error(1, 0, "invalid option -%c", optopt);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080097 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080098 }
99
Chris Fries4868b072014-10-06 11:24:54 -0500100 if (optind + 2 > argc) {
101 usage();
102 }
103
104 const char* device = argv[optind];
105 int fd;
106 if (strcmp(device, "-") == 0) {
Scott Anderson9e97fee2013-10-17 15:30:54 -0700107 fd = STDIN_FILENO;
108 } else {
Chris Fries4868b072014-10-06 11:24:54 -0500109 fd = open(device, read_only ? O_RDONLY : (O_RDWR | O_SYNC));
110 if (fd == -1) {
111 error(1, errno, "cannot open %s", argv[optind]);
Scott Anderson9e97fee2013-10-17 15:30:54 -0700112 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800113 }
114 optind++;
Chris Fries4868b072014-10-06 11:24:54 -0500115
116 // IOCTL(2) wants second parameter as a signed int.
117 // Let's let the user specify either negative numbers or large positive
118 // numbers, for the case where ioctl number is larger than INT_MAX.
119 errno = 0;
120 char* endp;
121 int ioctl_nr = UINT_MAX & strtoll(argv[optind], &endp, 0);
122 if (errno != 0 || *endp != '\0') {
123 error(1, errno, "couldn't parse ioctl number '%s'", argv[optind]);
124 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800125 optind++;
126
127 if(direct_arg) {
128 arg_size = 4;
129 length = 4;
130 }
131
132 if(length < 0) {
133 length = (argc - optind) * arg_size;
134 }
135 if(length) {
136 ioctl_args = calloc(1, length);
137
138 ioctl_argp_save = ioctl_argp = ioctl_args;
139 rem = length;
Chris Fries4868b072014-10-06 11:24:54 -0500140 while (optind < argc) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800141 uint64_t tmp = strtoull(argv[optind], NULL, 0);
Chris Fries4868b072014-10-06 11:24:54 -0500142 if (rem < arg_size) {
143 error(1, 0, "too many arguments");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800144 }
145 memcpy(ioctl_argp, &tmp, arg_size);
146 ioctl_argp += arg_size;
147 rem -= arg_size;
148 optind++;
149 }
150 }
151 printf("sending ioctl 0x%x", ioctl_nr);
152 rem = length;
153 while(rem--) {
154 printf(" 0x%02x", *ioctl_argp_save++);
155 }
Chris Fries4868b072014-10-06 11:24:54 -0500156 printf(" to %s\n", device);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800157
Chris Fries4868b072014-10-06 11:24:54 -0500158 int res;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800159 if(direct_arg)
160 res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
161 else if(length)
162 res = ioctl(fd, ioctl_nr, ioctl_args);
163 else
164 res = ioctl(fd, ioctl_nr, 0);
165 if (res < 0) {
Mark Salyzynaa907762014-05-08 09:31:43 -0700166 free(ioctl_args);
Chris Fries4868b072014-10-06 11:24:54 -0500167 error(1, errno, "ioctl 0x%x failed (returned %d)", ioctl_nr, res);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800168 }
Chris Fries4868b072014-10-06 11:24:54 -0500169
170 if (length) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800171 printf("return buf:");
172 ioctl_argp = ioctl_args;
173 rem = length;
174 while(rem--) {
175 printf(" %02x", *ioctl_argp++);
176 }
177 printf("\n");
178 }
Mark Salyzynaa907762014-05-08 09:31:43 -0700179 free(ioctl_args);
Chris Fries4868b072014-10-06 11:24:54 -0500180 close(fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800181 return 0;
182}