Home | History | Annotate | Download | only in toolbox
      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 
     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 
     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 
     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