• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
usage()43 static 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 }
52 
xstrtoi(const char * s,const char * what)53 static 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 
ioctl_main(int argc,char * argv[])66 int ioctl_main(int argc, char* argv[]) {
67     int read_only = 0;
68     int length = -1;
69     int arg_size = 4;
70     int direct_arg = 0;
71 
72     void *ioctl_args = NULL;
73     uint8_t *ioctl_argp;
74     uint8_t *ioctl_argp_save = NULL;
75     int rem;
76 
77     int c;
78     while ((c = getopt(argc, argv, "rdl:a:h")) != -1) {
79         switch (c) {
80         case 'r':
81             read_only = 1;
82             break;
83         case 'd':
84             direct_arg = 1;
85             break;
86         case 'l':
87             length = xstrtoi(optarg, "length");
88             break;
89         case 'a':
90             arg_size = xstrtoi(optarg, "argument size");
91             break;
92         case 'h':
93             usage();
94             break;
95         default:
96             error(1, 0, "invalid option -%c", optopt);
97         }
98     }
99 
100     if (optind + 2 > argc) {
101         usage();
102     }
103 
104     const char* device = argv[optind];
105     int fd;
106     if (strcmp(device, "-") == 0) {
107         fd = STDIN_FILENO;
108     } else {
109         fd = open(device, read_only ? O_RDONLY : (O_RDWR | O_SYNC));
110         if (fd == -1) {
111             error(1, errno, "cannot open %s", argv[optind]);
112         }
113     }
114     optind++;
115 
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     }
125     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;
140         while (optind < argc) {
141             uint64_t tmp = strtoull(argv[optind], NULL, 0);
142             if (rem < arg_size) {
143                 error(1, 0, "too many arguments");
144             }
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     }
156     printf(" to %s\n", device);
157 
158     int res;
159     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) {
166         free(ioctl_args);
167         error(1, errno, "ioctl 0x%x failed (returned %d)", ioctl_nr, res);
168     }
169 
170     if (length) {
171         printf("return buf:");
172         ioctl_argp = ioctl_args;
173         rem = length;
174         while(rem--) {
175             printf(" %02x", *ioctl_argp++);
176         }
177         printf("\n");
178     }
179     free(ioctl_args);
180     close(fd);
181     return 0;
182 }
183