summaryrefslogtreecommitdiffstats
path: root/toolbox/ioctl.c
blob: 73539d140e8349037859b907fa6e9d682bc1dd5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <getopt.h>
#include <string.h>
#include <linux/kd.h>
#include <linux/vt.h>
#include <errno.h>
#include <pthread.h>
#include <sys/ioctl.h>

int ioctl_main(int argc, char *argv[])
{
    int c;
    int fd;
    int res;

    int read_only = 0;
    int length = -1;
    int arg_size = 4;
    int direct_arg = 0;
    uint32_t ioctl_nr;
    void *ioctl_args = NULL;
    uint8_t *ioctl_argp;
    uint8_t *ioctl_argp_save = NULL;
    int rem;

    do {
        c = getopt(argc, argv, "rdl:a:h");
        if (c == EOF)
            break;
        switch (c) {
        case 'r':
            read_only = 1;
            break;
        case 'd':
            direct_arg = 1;
            break;
        case 'l':
            length = strtol(optarg, NULL, 0);
            break;
        case 'a':
            arg_size = strtol(optarg, NULL, 0);
            break;
        case 'h':
            fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
                    "  -l <length>   Length of io buffer\n"
                    "  -a <argsize>  Size of each argument (1-8)\n"
                    "  -r            Open device in read only mode\n"
                    "  -d            Direct argument (no iobuffer)\n"
                    "  -h            Print help\n", argv[0]);
            return -1;
        case '?':
            fprintf(stderr, "%s: invalid option -%c\n",
                argv[0], optopt);
            exit(1);
        }
    } while (1);

    if(optind + 2 > argc) {
        fprintf(stderr, "%s: too few arguments\n", argv[0]);
        exit(1);
    }

    if (!strcmp(argv[optind], "-")) {
        fd = STDIN_FILENO;
    } else {
        fd = open(argv[optind], read_only ? O_RDONLY : (O_RDWR | O_SYNC));
        if (fd < 0) {
            fprintf(stderr, "cannot open %s\n", argv[optind]);
            return 1;
        }
    }
    optind++;
    
    ioctl_nr = strtol(argv[optind], NULL, 0);
    optind++;

    if(direct_arg) {
        arg_size = 4;
        length = 4;
    }

    if(length < 0) {
        length = (argc - optind) * arg_size;
    }
    if(length) {
        ioctl_args = calloc(1, length);

        ioctl_argp_save = ioctl_argp = ioctl_args;
        rem = length;
        while(optind < argc) {
            uint64_t tmp = strtoull(argv[optind], NULL, 0);
            if(rem < arg_size) {
                fprintf(stderr, "%s: too many arguments\n", argv[0]);
                exit(1);
            }
            memcpy(ioctl_argp, &tmp, arg_size);
            ioctl_argp += arg_size;
            rem -= arg_size;
            optind++;
        }
    }
    printf("sending ioctl 0x%x", ioctl_nr);
    rem = length;
    while(rem--) {
        printf(" 0x%02x", *ioctl_argp_save++);
    }
    printf("\n");

    if(direct_arg)
        res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
    else if(length)
        res = ioctl(fd, ioctl_nr, ioctl_args);
    else
        res = ioctl(fd, ioctl_nr, 0);
    if (res < 0) {
        free(ioctl_args);
        fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res);
        return 1;
    }
    if(length) {
        printf("return buf:");
        ioctl_argp = ioctl_args;
        rem = length;
        while(rem--) {
            printf(" %02x", *ioctl_argp++);
        }
        printf("\n");
    }
    free(ioctl_args);
    return 0;
}