Skip to content

Commit d8216ff

Browse files
authored
Fix incoherent ioctl examples (#139)
Previously ioctl.c is a userspace program for chardev2.c and chardev.h [1]. But now, this file is an independent kernel module, and the original code disappear. This patch adds back the original userspace code and renames it to userspace_ioctl.c. [1] https://tldp.org/LDP/lkmpg/2.4/html/x856.html
1 parent fb15882 commit d8216ff

File tree

3 files changed

+114
-4
lines changed

3 files changed

+114
-4
lines changed

examples/chardev.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
* chardev.h - the header file with the ioctl definitions.
33
*
44
* The declarations here have to be in a header file, because they need
5-
* to be known both to the kernel module (in chardev.c) and the process
6-
* calling ioctl (ioctl.c).
5+
* to be known both to the kernel module (in chardev2.c) and the process
6+
* calling ioctl() (in userspace_ioctl.c).
77
*/
88

99
#ifndef CHARDEV_H
@@ -45,5 +45,6 @@
4545

4646
/* The name of the device file */
4747
#define DEVICE_FILE_NAME "char_dev"
48+
#define DEVICE_PATH "/dev/char_dev"
4849

4950
#endif

examples/other/userspace_ioctl.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
2+
/* userspace_ioctl.c - the process to use ioctl's to control the kernel module
3+
*
4+
* Until now we could have used cat for input and output. But now
5+
* we need to do ioctl's, which require writing our own process.
6+
*/
7+
8+
/* device specifics, such as ioctl numbers and the
9+
* major device file. */
10+
#include "../chardev.h"
11+
12+
#include <stdio.h> /* standard I/O */
13+
#include <fcntl.h> /* open */
14+
#include <unistd.h> /* close */
15+
#include <stdlib.h> /* exit */
16+
#include <sys/ioctl.h> /* ioctl */
17+
18+
/* Functions for the ioctl calls */
19+
20+
int ioctl_set_msg(int file_desc, char *message)
21+
{
22+
int ret_val;
23+
24+
ret_val = ioctl(file_desc, IOCTL_SET_MSG, message);
25+
26+
if (ret_val < 0) {
27+
printf("ioctl_set_msg failed:%d\n", ret_val);
28+
}
29+
30+
return ret_val;
31+
}
32+
33+
int ioctl_get_msg(int file_desc)
34+
{
35+
int ret_val;
36+
char message[100] = { 0 };
37+
38+
/* Warning - this is dangerous because we don't tell
39+
* the kernel how far it's allowed to write, so it
40+
* might overflow the buffer. In a real production
41+
* program, we would have used two ioctls - one to tell
42+
* the kernel the buffer length and another to give
43+
* it the buffer to fill
44+
*/
45+
ret_val = ioctl(file_desc, IOCTL_GET_MSG, message);
46+
47+
if (ret_val < 0) {
48+
printf("ioctl_get_msg failed:%d\n", ret_val);
49+
}
50+
printf("get_msg message:%s", message);
51+
52+
return ret_val;
53+
}
54+
55+
int ioctl_get_nth_byte(int file_desc)
56+
{
57+
int i, c;
58+
59+
printf("get_nth_byte message:");
60+
61+
i = 0;
62+
do {
63+
c = ioctl(file_desc, IOCTL_GET_NTH_BYTE, i++);
64+
65+
if (c < 0) {
66+
printf("\nioctl_get_nth_byte failed at the %d'th byte:\n", i);
67+
return c;
68+
}
69+
70+
putchar(c);
71+
} while (c != 0);
72+
73+
return 0;
74+
}
75+
76+
/* Main - Call the ioctl functions */
77+
int main(void)
78+
{
79+
int file_desc, ret_val;
80+
char *msg = "Message passed by ioctl\n";
81+
82+
file_desc = open(DEVICE_PATH, O_RDWR);
83+
if (file_desc < 0) {
84+
printf("Can't open device file: %s, error:%d\n", DEVICE_PATH,
85+
file_desc);
86+
exit(EXIT_FAILURE);
87+
}
88+
89+
ret_val = ioctl_set_msg(file_desc, msg);
90+
if (ret_val)
91+
goto error;
92+
ret_val = ioctl_get_nth_byte(file_desc);
93+
if (ret_val)
94+
goto error;
95+
ret_val = ioctl_get_msg(file_desc);
96+
if (ret_val)
97+
goto error;
98+
99+
close(file_desc);
100+
return 0;
101+
error:
102+
close(file_desc);
103+
exit(EXIT_FAILURE);
104+
}

lkmpg.tex

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,11 +1314,16 @@ \section{Talking To Device Files}
13141314

13151315
The ioctl function is called with three parameters: the file descriptor of the appropriate device file, the ioctl number, and a parameter, which is of type long so you can use a cast to use it to pass anything.
13161316
You will not be able to pass a structure this way, but you will be able to pass a pointer to the structure.
1317+
Here is an example:
13171318

1319+
\samplec{examples/ioctl.c}
1320+
1321+
You can see there is an argument called \cpp|cmd| in \cpp|test_ioctl_ioctl()| function.
1322+
It is the ioctl number.
13181323
The ioctl number encodes the major device number, the type of the ioctl, the command, and the type of the parameter.
13191324
This ioctl number is usually created by a macro call (\cpp|_IO|, \cpp|_IOR|, \cpp|_IOW| or \cpp|_IOWR| --- depending on the type) in a header file.
13201325
This header file should then be included both by the programs which will use ioctl (so they can generate the appropriate ioctl's) and by the kernel module (so it can understand it).
1321-
In the example below, the header file is chardev.h and the program which uses it is ioctl.c.
1326+
In the example below, the header file is \verb|chardev.h| and the program which uses it is \verb|userspace_ioctl.c|.
13221327

13231328
If you want to use ioctls in your own kernel modules, it is best to receive an official ioctl assignment, so if you accidentally get somebody else's ioctls, or if they get yours, you'll know something is wrong.
13241329
For more information, consult the kernel source tree at \src{Documentation/userspace-api/ioctl/ioctl-number.rst}.
@@ -1330,7 +1335,7 @@ \section{Talking To Device Files}
13301335

13311336
\samplec{examples/chardev.h}
13321337

1333-
\samplec{examples/ioctl.c}
1338+
\samplec{examples/other/userspace_ioctl.c}
13341339

13351340
\section{System Calls}
13361341
\label{sec:syscall}

0 commit comments

Comments
 (0)