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 43static 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 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} 65 66int 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