blob: ce6664b21ff1d3b91f5b15d726850c0aa2d7f9b6 [file] [log] [blame]
shu.wang56af1eb2022-03-16 09:58:39 +08001/*
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>
34#include <fcntl.h>
35#include <getopt.h>
36#include <stdio.h>
37#include <stdint.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/ioctl.h>
41#include <unistd.h>
42#include <limits.h>
43
44static void usage() {
45 fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
46 " -l <length> Length of io buffer\n"
47 " -a <argsize> Size of each argument (1-8)\n"
48 " -r Open device in read only mode\n"
49 " -d Direct argument (no iobuffer)\n"
50 " -h Print help\n", "ioctl");
51 exit(1);
52}
53
54static int xstrtoi(const char* s, const char* what) {
55 char* endp;
56 errno = 0;
57 long result = strtol(s, &endp, 0);
58 if (errno != 0 || *endp != '\0') {
59 error(1, errno, "couldn't parse %s '%s'", what, s);
60 }
61 if (result > INT_MAX || result < INT_MIN) {
62 error(1, errno, "%s '%s' out of range", what, s);
63 }
64 return result;
65}
66
67int main(int argc, char* argv[]) {
68 int read_only = 0;
69 int length = -1;
70 int arg_size = 4;
71 int direct_arg = 0;
72
73 void *ioctl_args = NULL;
74 uint8_t *ioctl_argp;
75 uint8_t *ioctl_argp_save = NULL;
76 int rem;
77
78 int c;
79 while ((c = getopt(argc, argv, "rdl:a:h")) != -1) {
80 switch (c) {
81 case 'r':
82 read_only = 1;
83 break;
84 case 'd':
85 direct_arg = 1;
86 break;
87 case 'l':
88 length = xstrtoi(optarg, "length");
89 break;
90 case 'a':
91 arg_size = xstrtoi(optarg, "argument size");
92 break;
93 case 'h':
94 usage();
95 break;
96 default:
97 error(1, 0, "invalid option -%c", optopt);
98 }
99 }
100
101 if (optind + 2 > argc) {
102 usage();
103 }
104
105 const char* device = argv[optind];
106 int fd;
107 if (strcmp(device, "-") == 0) {
108 fd = STDIN_FILENO;
109 } else {
110 fd = open(device, read_only ? O_RDONLY : (O_RDWR | O_SYNC));
111 if (fd == -1) {
112 error(1, errno, "cannot open %s", argv[optind]);
113 }
114 }
115 optind++;
116
117 // IOCTL(2) wants second parameter as a signed int.
118 // Let's let the user specify either negative numbers or large positive
119 // numbers, for the case where ioctl number is larger than INT_MAX.
120 errno = 0;
121 char* endp;
122 int ioctl_nr = UINT_MAX & strtoll(argv[optind], &endp, 0);
123 if (errno != 0 || *endp != '\0') {
124 error(1, errno, "couldn't parse ioctl number '%s'", argv[optind]);
125 }
126 optind++;
127
128 if (direct_arg) {
129 arg_size = 4;
130 length = 4;
131 }
132
133 if (length < 0) {
134 length = (argc - optind) * arg_size;
135 }
136 if (length) {
137 ioctl_args = calloc(1, length);
138
139 ioctl_argp_save = ioctl_argp = ioctl_args;
140 rem = length;
141 while (optind < argc) {
142 uint64_t tmp = strtoull(argv[optind], NULL, 0);
143 if (rem < arg_size) {
144 error(1, 0, "too many arguments");
145 }
146 memcpy(ioctl_argp, &tmp, arg_size);
147 ioctl_argp += arg_size;
148 rem -= arg_size;
149 optind++;
150 }
151 }
152 printf("sending ioctl 0x%x", ioctl_nr);
153 rem = length;
154 while (rem--) {
155 printf(" 0x%02x", *ioctl_argp_save++);
156 }
157 printf(" to %s\n", device);
158
159 int res;
160 if (direct_arg)
161 res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
162 else if (length)
163 res = ioctl(fd, ioctl_nr, ioctl_args);
164 else
165 res = ioctl(fd, ioctl_nr, 0);
166 if (res < 0) {
167 free(ioctl_args);
168 error(1, errno, "ioctl 0x%x failed (returned %d)", ioctl_nr, res);
169 }
170
171 if (length) {
172 printf("return buf:");
173 ioctl_argp = ioctl_args;
174 rem = length;
175 while (rem--) {
176 printf(" %02x", *ioctl_argp++);
177 }
178 printf("\n");
179 }
180 free(ioctl_args);
181 close(fd);
182 return 0;
183}
184