mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 10:15:57 +01:00
ioctl example complete!
This commit is contained in:
@@ -1,13 +1,12 @@
|
||||
/*
|
||||
Give integer and a pointer to the kernel, and get one positive integer out.
|
||||
Input: an integer (with some annoying restrictions) and a pointer
|
||||
|
||||
Feels like an archaic API... so many weird restrictions for something that could be so simple!
|
||||
Output:
|
||||
|
||||
TODO: must the ioctl numbers be globally unique? How to ensure that?
|
||||
- positive integer return value, which for sanity should only be used with negative values for success
|
||||
- the input pointer data may be overwritten to contain output
|
||||
|
||||
Ioctl is super picky about the ioctl numbers, it is very annoying: https://stackoverflow.com/questions/10071296/ioctl-is-not-called-if-cmd-2
|
||||
|
||||
See how do_vfs_ioctl highjacks several values. This "forces" use to use the _IOx macros...
|
||||
Feels like an archaic API... so many weird restrictions and types for something that could be so simple!
|
||||
|
||||
Documentation/ioctl/ioctl-number.txt has some info:
|
||||
|
||||
@@ -17,18 +16,54 @@ Documentation/ioctl/ioctl-number.txt has some info:
|
||||
_IOWR an ioctl with both write and read parameters.
|
||||
*/
|
||||
|
||||
#include <asm/uaccess.h> /* copy_from_user, copy_to_user */
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/printk.h> /* printk */
|
||||
|
||||
#include "ioctl.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static struct dentry *dir;
|
||||
|
||||
static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long argp)
|
||||
{
|
||||
pr_info("cmd = %u\n", cmd);
|
||||
return cmd + 1;
|
||||
void __user *arg_user;
|
||||
union {
|
||||
int i;
|
||||
lkmc_ioctl_struct s;
|
||||
} arg_kernel;
|
||||
|
||||
arg_user = (void __user *)argp;
|
||||
pr_info("cmd = %x\n", cmd);
|
||||
switch (cmd) {
|
||||
case LKMC_IOCTL_INC:
|
||||
if (copy_from_user(&arg_kernel.i, arg_user, sizeof(arg_kernel.i))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
pr_info("0 arg = %d\n", arg_kernel.i);
|
||||
arg_kernel.i += 1;
|
||||
if (copy_to_user(arg_user, &arg_kernel.i, sizeof(arg_kernel.i))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
break;
|
||||
case LKMC_IOCTL_INC_DEC:
|
||||
if (copy_from_user(&arg_kernel.s, arg_user, sizeof(arg_kernel.s))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
pr_info("1 arg = %d %d\n", arg_kernel.s.i, arg_kernel.s.j);
|
||||
arg_kernel.s.i += 1;
|
||||
arg_kernel.s.j -= 1;
|
||||
if (copy_to_user(arg_user, &arg_kernel.s, sizeof(arg_kernel.s))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations fops = {
|
||||
|
||||
@@ -3,6 +3,30 @@
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#define IOCTL0 _IOW(123, 0, char *)
|
||||
/* Structs are the way to pass multiple arguments. */
|
||||
typedef struct {
|
||||
int i;
|
||||
int j;
|
||||
} lkmc_ioctl_struct;
|
||||
|
||||
/* Some random number I can't understand how to choose. */
|
||||
#define LKMC_IOCTL_MAGIC 0x33
|
||||
|
||||
/*
|
||||
* I think those number does not *need* to be unique across, that is just to help debugging:
|
||||
* https://stackoverflow.com/questions/22496123/what-is-the-meaning-of-this-macro-iormy-macig-0-int
|
||||
*
|
||||
* However, the ioctl syscall highjacks several low values at do_vfs_ioctl, e.g.
|
||||
* This "forces" use to use the _IOx macros...
|
||||
* https://stackoverflow.com/questions/10071296/ioctl-is-not-called-if-cmd-2
|
||||
*
|
||||
* Some of those magic low values are used for fnctl, which can also be used on regular files:
|
||||
* e.g. FIOCLEX for close-on-exec:
|
||||
* https://stackoverflow.com/questions/6125068/what-does-the-fd-cloexec-fcntl-flag-do
|
||||
*
|
||||
* TODO are the W or R of _IOx and type functional, or only to help with uniqueness?
|
||||
* */
|
||||
#define LKMC_IOCTL_INC _IOWR(LKMC_IOCTL_MAGIC, 0, int)
|
||||
#define LKMC_IOCTL_INC_DEC _IOWR(LKMC_IOCTL_MAGIC, 1, lkmc_ioctl_struct)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd, ret;
|
||||
int fd, arg_int, ret;
|
||||
lkmc_ioctl_struct arg_struct;
|
||||
|
||||
if (argc < 4) {
|
||||
puts("Usage: ./prog <ioctl-file> <cmd> <arg>");
|
||||
@@ -23,13 +24,32 @@ int main(int argc, char **argv)
|
||||
perror("open");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ret = ioctl(fd, IOCTL0, argv[3]);
|
||||
if (ret == -1) {
|
||||
perror("ioctl");
|
||||
return EXIT_FAILURE;
|
||||
/* 0 */
|
||||
{
|
||||
arg_int = 1;
|
||||
ret = ioctl(fd, LKMC_IOCTL_INC, &arg_int);
|
||||
if (ret == -1) {
|
||||
perror("ioctl");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("arg = %d\n", arg_int);
|
||||
printf("ret = %d\n", ret);
|
||||
printf("errno = %d\n", errno);
|
||||
}
|
||||
puts("");
|
||||
/* 1 */
|
||||
{
|
||||
arg_struct.i = 1;
|
||||
arg_struct.j = 1;
|
||||
ret = ioctl(fd, LKMC_IOCTL_INC_DEC, &arg_struct);
|
||||
if (ret == -1) {
|
||||
perror("ioctl");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("arg = %d %d\n", arg_struct.i, arg_struct.j);
|
||||
printf("ret = %d\n", ret);
|
||||
printf("errno = %d\n", errno);
|
||||
}
|
||||
printf("ret = %d\n", ret);
|
||||
printf("errno = %d\n", errno);
|
||||
close(fd);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user