summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--toolbox/ioctl.c145
1 files changed, 96 insertions, 49 deletions
diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c
index d1cc14a08..093e467de 100644
--- a/toolbox/ioctl.c
+++ b/toolbox/ioctl.c
@@ -1,36 +1,81 @@
1#include <stdio.h> 1/*
2#include <stdlib.h> 2 * Copyright (c) 2008, The Android Open Source Project
3#include <stdint.h> 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>
4#include <fcntl.h> 34#include <fcntl.h>
5#include <getopt.h> 35#include <getopt.h>
36#include <stdio.h>
37#include <stdint.h>
38#include <stdlib.h>
6#include <string.h> 39#include <string.h>
7#include <linux/kd.h>
8#include <linux/vt.h>
9#include <errno.h>
10#include <pthread.h>
11#include <sys/ioctl.h> 40#include <sys/ioctl.h>
12#include <unistd.h> 41#include <unistd.h>
13 42
14int ioctl_main(int argc, char *argv[]) 43static void usage() {
15{ 44 fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
16 int c; 45 " -l <length> Length of io buffer\n"
17 int fd; 46 " -a <argsize> Size of each argument (1-8)\n"
18 int res; 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
53static 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}
19 65
66int ioctl_main(int argc, char* argv[]) {
20 int read_only = 0; 67 int read_only = 0;
21 int length = -1; 68 int length = -1;
22 int arg_size = 4; 69 int arg_size = 4;
23 int direct_arg = 0; 70 int direct_arg = 0;
24 uint32_t ioctl_nr; 71
25 void *ioctl_args = NULL; 72 void *ioctl_args = NULL;
26 uint8_t *ioctl_argp; 73 uint8_t *ioctl_argp;
27 uint8_t *ioctl_argp_save = NULL; 74 uint8_t *ioctl_argp_save = NULL;
28 int rem; 75 int rem;
29 76
30 do { 77 int c;
31 c = getopt(argc, argv, "rdl:a:h"); 78 while ((c = getopt(argc, argv, "rdl:a:h")) != -1) {
32 if (c == EOF)
33 break;
34 switch (c) { 79 switch (c) {
35 case 'r': 80 case 'r':
36 read_only = 1; 81 read_only = 1;
@@ -39,43 +84,44 @@ int ioctl_main(int argc, char *argv[])
39 direct_arg = 1; 84 direct_arg = 1;
40 break; 85 break;
41 case 'l': 86 case 'l':
42 length = strtol(optarg, NULL, 0); 87 length = xstrtoi(optarg, "length");
43 break; 88 break;
44 case 'a': 89 case 'a':
45 arg_size = strtol(optarg, NULL, 0); 90 arg_size = xstrtoi(optarg, "argument size");
46 break; 91 break;
47 case 'h': 92 case 'h':
48 fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n" 93 usage();
49 " -l <length> Length of io buffer\n" 94 break;
50 " -a <argsize> Size of each argument (1-8)\n" 95 default:
51 " -r Open device in read only mode\n" 96 error(1, 0, "invalid option -%c", optopt);
52 " -d Direct argument (no iobuffer)\n"
53 " -h Print help\n", argv[0]);
54 return -1;
55 case '?':
56 fprintf(stderr, "%s: invalid option -%c\n",
57 argv[0], optopt);
58 exit(1);
59 } 97 }
60 } while (1); 98 }
61 99
62 if(optind + 2 > argc) { 100 if (optind + 2 > argc) {
63 fprintf(stderr, "%s: too few arguments\n", argv[0]); 101 usage();
64 exit(1);
65 } 102 }
66 103
67 if (!strcmp(argv[optind], "-")) { 104 const char* device = argv[optind];
105 int fd;
106 if (strcmp(device, "-") == 0) {
68 fd = STDIN_FILENO; 107 fd = STDIN_FILENO;
69 } else { 108 } else {
70 fd = open(argv[optind], read_only ? O_RDONLY : (O_RDWR | O_SYNC)); 109 fd = open(device, read_only ? O_RDONLY : (O_RDWR | O_SYNC));
71 if (fd < 0) { 110 if (fd == -1) {
72 fprintf(stderr, "cannot open %s\n", argv[optind]); 111 error(1, errno, "cannot open %s", argv[optind]);
73 return 1;
74 } 112 }
75 } 113 }
76 optind++; 114 optind++;
77 115
78 ioctl_nr = strtol(argv[optind], NULL, 0); 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 }
79 optind++; 125 optind++;
80 126
81 if(direct_arg) { 127 if(direct_arg) {
@@ -91,11 +137,10 @@ int ioctl_main(int argc, char *argv[])
91 137
92 ioctl_argp_save = ioctl_argp = ioctl_args; 138 ioctl_argp_save = ioctl_argp = ioctl_args;
93 rem = length; 139 rem = length;
94 while(optind < argc) { 140 while (optind < argc) {
95 uint64_t tmp = strtoull(argv[optind], NULL, 0); 141 uint64_t tmp = strtoull(argv[optind], NULL, 0);
96 if(rem < arg_size) { 142 if (rem < arg_size) {
97 fprintf(stderr, "%s: too many arguments\n", argv[0]); 143 error(1, 0, "too many arguments");
98 exit(1);
99 } 144 }
100 memcpy(ioctl_argp, &tmp, arg_size); 145 memcpy(ioctl_argp, &tmp, arg_size);
101 ioctl_argp += arg_size; 146 ioctl_argp += arg_size;
@@ -108,8 +153,9 @@ int ioctl_main(int argc, char *argv[])
108 while(rem--) { 153 while(rem--) {
109 printf(" 0x%02x", *ioctl_argp_save++); 154 printf(" 0x%02x", *ioctl_argp_save++);
110 } 155 }
111 printf("\n"); 156 printf(" to %s\n", device);
112 157
158 int res;
113 if(direct_arg) 159 if(direct_arg)
114 res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args); 160 res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
115 else if(length) 161 else if(length)
@@ -118,10 +164,10 @@ int ioctl_main(int argc, char *argv[])
118 res = ioctl(fd, ioctl_nr, 0); 164 res = ioctl(fd, ioctl_nr, 0);
119 if (res < 0) { 165 if (res < 0) {
120 free(ioctl_args); 166 free(ioctl_args);
121 fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res); 167 error(1, errno, "ioctl 0x%x failed (returned %d)", ioctl_nr, res);
122 return 1;
123 } 168 }
124 if(length) { 169
170 if (length) {
125 printf("return buf:"); 171 printf("return buf:");
126 ioctl_argp = ioctl_args; 172 ioctl_argp = ioctl_args;
127 rem = length; 173 rem = length;
@@ -131,5 +177,6 @@ int ioctl_main(int argc, char *argv[])
131 printf("\n"); 177 printf("\n");
132 } 178 }
133 free(ioctl_args); 179 free(ioctl_args);
180 close(fd);
134 return 0; 181 return 0;
135} 182}