Skip to content

Commit d840b0c

Browse files
committed
ioctl: move doc to README
1 parent 084e3fa commit d840b0c

File tree

7 files changed

+107
-51
lines changed

7 files changed

+107
-51
lines changed

README.adoc

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3094,6 +3094,57 @@ ab
30943094
cd
30953095
....
30963096

3097+
==== ioctl
3098+
3099+
In guest:
3100+
3101+
....
3102+
/ioctl.sh
3103+
echo $?
3104+
....
3105+
3106+
Outcome: the test passes:
3107+
3108+
....
3109+
0
3110+
....
3111+
3112+
Sources:
3113+
3114+
* link:kernel_module/ioctl.c[]
3115+
* link:kernel_module/ioctl.h[]
3116+
* link:kernel_module/user/ioctl.c[]
3117+
* link:rootfs_overlay/ioctl.sh[]
3118+
3119+
The `ioctl` system call is the best ways to provide an arbitrary number of parameters to the kernel in a single go.
3120+
3121+
It is therefore one of the most important methods of communication with real device drivers, which often take several fields as input.
3122+
3123+
`ioctl` takes as input:
3124+
3125+
* an integer `request` : it usually identifies what type of operation we want to do on this call
3126+
* an untyped pointer to memory: can be anything, but is typically a pointer to a `struct`
3127+
+
3128+
The type of the `struct` often depends on the `request` input
3129+
+
3130+
This `struct` is defined on a uapi-style C header that is used both to compile the kernel module and the userland executable.
3131+
+
3132+
The fields of this `struct` can be thought of as arbitrary input parameters.
3133+
3134+
And the output is:
3135+
3136+
* an integer return value. `man ioctl` documents:
3137+
+
3138+
____
3139+
Usually, on success zero is returned. A few `ioctl()` requests use the return value as an output parameter and return a nonnegative value on success. On error, -1 is returned, and errno is set appropriately.
3140+
____
3141+
* the input pointer data may be overwritten to contain arbitrary output
3142+
3143+
Bibliography:
3144+
3145+
* https://stackoverflow.com/questions/2264384/how-do-i-use-ioctl-to-manipulate-my-kernel-module/44613896#44613896
3146+
* https://askubuntu.com/questions/54239/problem-with-ioctl-in-a-simple-kernel-module/926675#926675
3147+
30973148
==== Character devices
30983149

30993150
In guest:
@@ -3193,7 +3244,7 @@ Sources:
31933244
* link:kernel_module/user/anonymous_inode.c[]
31943245
* link:rootfs_overlay/anonymous_inode.sh[]
31953246

3196-
This example gets an anonymous inode via `ioctl` from a debugfs entry by using `anon_inode_getfd`.
3247+
This example gets an anonymous inode via <<ioctl>> from a debugfs entry by using `anon_inode_getfd`.
31973248

31983249
Reads to that inode return the sequence: `1`, `10`, `100`, ... `10000000`, `1`, `100`, ...
31993250

kernel_module/README.adoc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
... link:dep.c[]
2020
... link:dep2.c[]
2121
. Pseudo filesystems
22-
.. link:ioctl.c[]
2322
.. link:mmap.c[]
2423
.. link:poll.c[]
2524
. Asynchronous

kernel_module/ioctl.c

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,4 @@
1-
/*
2-
Input: an integer (with some annoying restrictions) and a pointer
3-
4-
Output:
5-
6-
- positive integer return value, which for sanity should only be used with negative values for success
7-
- the input pointer data may be overwritten to contain output
8-
9-
Feels like an archaic API... so many weird restrictions and types for something that could be so simple!
10-
11-
Documentation/ioctl/ioctl-number.txt has some info:
12-
13-
_IO an ioctl with no parameters
14-
_IOW an ioctl with write parameters (copy_from_user)
15-
_IOR an ioctl with read parameters (copy_to_user)
16-
_IOWR an ioctl with both write and read parameters.
17-
18-
- https://stackoverflow.com/questions/2264384/how-do-i-use-ioctl-to-manipulate-my-kernel-module/44613896#44613896
19-
- https://askubuntu.com/questions/54239/problem-with-ioctl-in-a-simple-kernel-module/926675#926675
20-
*/
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#ioctl */
212

223
#include <linux/debugfs.h>
234
#include <linux/module.h>

kernel_module/ioctl.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ typedef struct {
99
int j;
1010
} lkmc_ioctl_struct;
1111

12-
/* Some random number I can't understand how to choose. */
12+
/* TODO some random number I can't understand how to choose. */
1313
#define LKMC_IOCTL_MAGIC 0x33
1414

15-
/*
16-
* I think those number does not *need* to be unique across, that is just to help debugging:
15+
/* I think those number do not *need* to be unique across, that is just to help debugging:
1716
* https://stackoverflow.com/questions/22496123/what-is-the-meaning-of-this-macro-iormy-macig-0-int
1817
*
1918
* However, the ioctl syscall highjacks several low values at do_vfs_ioctl, e.g.
@@ -25,8 +24,19 @@ typedef struct {
2524
* https://stackoverflow.com/questions/6125068/what-does-the-fd-cloexec-fcntl-flag-do
2625
*
2726
* TODO are the W or R of _IOx and type functional, or only to help with uniqueness?
28-
* */
27+
*
28+
* Documentation/ioctl/ioctl-number.txt documents:
29+
*
30+
* ....
31+
* _IO an ioctl with no parameters
32+
* _IOW an ioctl with write parameters (copy_from_user)
33+
* _IOR an ioctl with read parameters (copy_to_user)
34+
* _IOWR an ioctl with both write and read parameters.
35+
* ....
36+
*/
37+
/* Take an int, increment it. */
2938
#define LKMC_IOCTL_INC _IOWR(LKMC_IOCTL_MAGIC, 0, int)
39+
/* Take a struct with two ints, increment the first, and decrement the second. */
3040
#define LKMC_IOCTL_INC_DEC _IOWR(LKMC_IOCTL_MAGIC, 1, lkmc_ioctl_struct)
3141

3242
#endif

kernel_module/user/ioctl.c

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#ioctl */
2+
13
#define _GNU_SOURCE
24
#include <errno.h>
35
#include <fcntl.h>
@@ -12,43 +14,53 @@
1214

1315
int main(int argc, char **argv)
1416
{
15-
int fd, arg_int, ret;
17+
char *ioctl_path;
18+
int fd, request, arg0, arg1, arg_int, ret;
1619
lkmc_ioctl_struct arg_struct;
1720

1821
if (argc < 2) {
19-
puts("Usage: ./prog <ioctl-file>");
22+
puts("Usage: ./prog <ioctl-file> <request> [<arg>...]");
2023
return EXIT_FAILURE;
2124
}
22-
fd = open(argv[1], O_RDONLY);
25+
ioctl_path = argv[1];
26+
request = strtol(argv[2], NULL, 10);
27+
if (argc > 3) {
28+
arg0 = strtol(argv[3], NULL, 10);
29+
}
30+
if (argc > 4) {
31+
arg1 = strtol(argv[4], NULL, 10);
32+
}
33+
34+
fd = open(ioctl_path, O_RDONLY);
2335
if (fd == -1) {
2436
perror("open");
2537
return EXIT_FAILURE;
2638
}
27-
/* 0 */
39+
switch (request)
2840
{
29-
arg_int = 1;
30-
ret = ioctl(fd, LKMC_IOCTL_INC, &arg_int);
31-
if (ret == -1) {
32-
perror("ioctl");
41+
case 0:
42+
arg_int = arg0;
43+
ret = ioctl(fd, LKMC_IOCTL_INC, &arg_int);
44+
if (ret != -1) {
45+
printf("%d\n", arg_int);
46+
}
47+
break;
48+
case 1:
49+
arg_struct.i = arg0;
50+
arg_struct.j = arg1;
51+
ret = ioctl(fd, LKMC_IOCTL_INC_DEC, &arg_struct);
52+
if (ret != -1) {
53+
printf("%d %d\n", arg_struct.i, arg_struct.j);
54+
}
55+
break;
56+
default:
57+
puts("error: unknown request");
3358
return EXIT_FAILURE;
34-
}
35-
printf("arg = %d\n", arg_int);
36-
printf("ret = %d\n", ret);
37-
printf("errno = %d\n", errno);
3859
}
39-
puts("");
40-
/* 1 */
41-
{
42-
arg_struct.i = 1;
43-
arg_struct.j = 1;
44-
ret = ioctl(fd, LKMC_IOCTL_INC_DEC, &arg_struct);
45-
if (ret == -1) {
46-
perror("ioctl");
47-
return EXIT_FAILURE;
48-
}
49-
printf("arg = %d %d\n", arg_struct.i, arg_struct.j);
50-
printf("ret = %d\n", ret);
60+
if (ret == -1) {
61+
perror("ioctl");
5162
printf("errno = %d\n", errno);
63+
return EXIT_FAILURE;
5264
}
5365
close(fd);
5466
return EXIT_SUCCESS;

rootfs_overlay/ioctl.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#!/bin/sh
22
set -e
3+
f=/sys/kernel/debug/lkmc_ioctl
34
insmod /ioctl.ko
4-
/ioctl.out /sys/kernel/debug/lkmc_ioctl
5+
[ "$(/ioctl.out "$f" 0 1)" = 2 ]
6+
[ "$(/ioctl.out "$f" 1 1 1)" = '2 0' ]
57
rmmod ioctl

rootfs_overlay/test_all.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ for test in \
55
/character_device_create.sh \
66
/debugfs.sh \
77
/fops.sh \
8+
/ioctl.sh \
89
/procfs.sh \
910
/seq_file.sh \
1011
/seq_file_single_open.sh \

0 commit comments

Comments
 (0)