ioctl call program compiling error - c

I want to call kernel module driver.ko ioctl from user space with c program. when compiling I got this error
header.h:13:38: error: expected expression before ‘char’
#define IOCTL_CMD _IORW(MAGIC_NO, 0, char *)
by definition I put the right arguments : _IORW(int type, int number, data_type)
main.c
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include "header.h"
int main()
{
int fd;
char * msg = "5";
fd = open(DEVICE_PATH, O_RDWR);
ioctl(fd, IOCTL_CMD, msg);
printf("ioctl executed\n");
close(fd);
return 0;
}
header.h
#include <linux/ioctl.h>
#include <linux/kdev_t.h> /* for MKDEV */
#define DEVICE_NAME "driver"
#define DEVICE_PATH "/dev/driver"
#define WRITE 0
static int major_no;
#define MAGIC_NO '4'
/*
* Set the message of the device driver
*/
#define IOCTL_CMD _IORW(MAGIC_NO, 0, char *)

The macro _IORW doesn't seem to exist in the Linux headers, try using _IOWR instead. Also I don't think you're use of char * is correct here. That would imply the last parameter to ioctl is the address of a char * variable, not a string.

Related

How to read file from kernel

I want to read file from kernel module which contains some parameters
I used the following source code
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/fs.h> // Needed by filp
#include <linux/rbtree.h>
#include <linux/time.h>
#include <linux/atomic.h>
#include <linux/proc_fs.h>
#include <linux/jiffies.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <linux/inetdevice.h>
#include <linux/if_ether.h>
int init_module(void)
{
// Create variables
struct file *f;
char buf[128];
mm_segment_t fs;
int i;
unsigned long long offset = 0;
// Init the buffer with 0
for(i=0;i<128;i++)
buf[i] = 0;
// To see in /var/log/messages that the module is operating
// I am using Fedora and for the test I have chosen following file
// Obviously it is much smaller than the 128 bytes, but hell with it =)
f = filp_open("/etc/lsb-release", O_RDONLY, 0);
if(f == NULL)
printk(KERN_ALERT "filp_open error!!.\n");
else{
// Get current segment descriptor
fs = get_fs();
// Set segment descriptor associated to kernel space
set_fs(get_ds());
// Read the file
f->f_op->read(f, buf, 128, &f->f_pos);
// Restore segment descriptor
set_fs(fs);
// See what we read from file
printk(KERN_INFO "buf:%s\n",buf);
}
filp_close(f,NULL);
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "My module is unloaded\n");
}
But this function crash. I debug it and I found that f->f_op->read is NULL
My kernel version is 4.15 and my ubuntu is 16
What I am missing?
Why f->f_op->read is NULL ?
How to read some parameter from user space in the load of module ? I think better to use file. If so, How to read file in kernel ?

Why can't I access uname struct's domainname member even if I defined _GNU_SOURCE

I am trying to some get Linux kernel version information by calling uname system call, but I am getting a compiler error saying ‘struct utsname’ has no member named ‘domainname’
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/utsname.h>
#define _GNU_SOURCE
int main(void) {
struct utsname buffer;
errno = 0;
if (uname(&buffer) != 0) {
perror("uname");
exit(EXIT_FAILURE);
}
printf("system name = %s\n", buffer.sysname);
printf("node name = %s\n", buffer.nodename);
printf("release = %s\n", buffer.release);
printf("version = %s\n", buffer.version);
printf("machine = %s\n", buffer.machine);
#ifdef _GNU_SOURCE
printf("domain name = %s\n", buffer.domainname);
#endif
return EXIT_SUCCESS;
}
according to https://linux.die.net/man/2/uname struct utsname is
struct utsname {
char sysname[]; /* Operating system name (e.g., "Linux") */
char nodename[]; /* Name within "some implementation-defined
network" */
char release[]; /* Operating system release (e.g., "2.6.28") */
char version[]; /* Operating system version */
char machine[]; /* Hardware identifier */
#ifdef _GNU_SOURCE
char domainname[]; /* NIS or YP domain name */
#endif
};
I am not sure what I missed here
From man feature_test_macros:
NOTE: In order to be effective, a feature test macro must be defined
before including any header files
It's:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/utsname.h>

How can I compile an application that can use the read/write hints in kernel?

I am trying to compile an simple application that uses the read-write hint, here is the code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdint.h>
static char const filename[] = "./file.txt";
static char const message[] = "/mnt/pool/my_file\n";
int main(void)
{
int fp;
int cnt = 0;
errno = 0;
//uint64_t type = RWH_WRITE_LIFE_MEDIUM; <-- [!] not working
uint64_t type = 3;
fp = open(filename, O_WRONLY | O_CREAT);
if (fp == -1)
return 1;
//fcntl(fp, F_SET_RW_HINT, &type); <-- [!] not working
fcntl(fp, (1024+12), &type);
cnt = write(fp, message, sizeof(message));
if(cnt == -1)
return 1;
close(fp);
return 0;
}
I've found that the RWH_WRITE_LIFE_MEDIUM is defined at include/uapi/linux/fcntl.h, but I do not know what to do to be able to compile with this options.
Any ideas in how can I compile this without error?
EDIT 1:
Ok, I followed the instructions where I included the #include <linux/fcntl.h> and the #define _GNU_SOURCE and now I get this error:
$ gcc open_file_fcntl.c
In file included from /usr/include/fcntl.h:35:0,
from open_file_fcntl.c:7:
/usr/include/x86_64-linux-gnu/bits/fcntl.h:35:8: error: redefinition of ‘struct flock’
struct flock
^~~~~
In file included from /usr/include/x86_64-linux-gnu/asm/fcntl.h:1:0,
from /usr/include/linux/fcntl.h:5,
from open_file_fcntl.c:6:
/usr/include/asm-generic/fcntl.h:196:8: note: originally defined here
struct flock {
^~~~~
I am using kernel 5.0.0-23-generic, and gcc --version 7.4.0.
Also tested on a QEMU environment using kernel 4.14.78, and gcc --version 4.8.4.
The simplest solution is to define the _GNU_SOURCE macro before #include <fcntl.h>. As there may be other interactions, it is better to define it before any #include directives:
open_file_fcntl.c
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdint.h>
static char const filename[] = "./file.txt";
static char const message[] = "/mnt/pool/my_file\n";
int main(void)
{
int fp;
int cnt = 0;
errno = 0;
uint64_t type = RWH_WRITE_LIFE_MEDIUM;
fp = open(filename, O_WRONLY | O_CREAT);
if (fp == -1)
return 1;
fcntl(fp, F_SET_RW_HINT, &type);
cnt = write(fp, message, sizeof(message));
if(cnt == -1)
return 1;
close(fp);
return 0;
}
Alternatively, the #define _GNU_SOURCE can be removed from the source code (open_file_fcntl.c above) and the macro defined on the compiler command line:
$ gcc -D_GNU_SOURCE open_file_fcntl.c
These are Linux-specific flags, so you need to either pass -D_GNU_SOURCE to the compiler or put #define _GNU_SOURCE at the top of your source file.
After following the other answer, I got a different problem, and for that, I could reach the final solution.
By checking both definitions of the struct flock in the above-mentioned locations, there is a #define that can be set at the application layer to avoid the redefinition, which is the #define HAVE_ARCH_STRUCT_FLOCK.
It must be added in between the fcntl.h includes.
Here is the complete code:
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#define HAVE_ARCH_STRUCT_FLOCK
#include <linux/fcntl.h>
static char const filename[] = "./file.txt";
static char const message[] = "/mnt/pool/my_file\n";
int main(void)
{
int fp;
int cnt = 0;
uint64_t type = RWH_WRITE_LIFE_MEDIUM;
fp = open(filename, O_WRONLY | O_CREAT);
if (fp == -1)
return 1;
fcntl(fp, F_SET_RW_HINT, &type);
cnt = write(fp, message, sizeof(message));
if(cnt == -1)
return 1;
close(fp);
return 0;
}

Why does mmap defined in a Linux kernel module return MAP_FAILED?

I am trying to map a kernel buffer in user space using mmap method in linux 3.10.10. But it is returning MAP_FAILED. Why it is failed to map the buffer.
Kernel module
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_ALERT */
#include <linux/init.h> /* Needed for the macros */
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/io.h>
//#include <linux/malloc.h>
#include <linux/mm.h> /* mmap related stuff */
long long *buf1;
long long* buf;
static int driver_mmap(struct file *file, struct vm_area_struct *vma)
{
vma->vm_flags |= VM_LOCKED|VM_SHARED;
int i = remap_pfn_range(vma, vma->vm_start,
virt_to_phys(buf) >> PAGE_SHIFT,
vma->vm_end-vma->vm_start, vma->vm_page_prot);
SetPageReserved(virt_to_page(buf));
printk("MMAP \n");
return 0;
}
struct file_operations proc_fops =
{
mmap:driver_mmap,
};
int init_module_test(void)
{
int i;
buf1 = kmalloc(4096, __GFP_COLD|GFP_DMA);
buf = ((int)buf1 + PAGE_SIZE -1) & PAGE_MASK;
printk("<1>Hello world1\n");
for (i = 0; i < 512; i++)
{
buf[i] = (long long) i + 1;
}
proc_create ("mmap_example",0,NULL, &proc_fops);
printk("<1>Hello world3\n");
printk("<1>BUF1 = 0x%08x\n BUF = 0x%08x\n", buf1,buf);
return 0;
}
void cleanup_module_test(void)
{
remove_proc_entry ("mmap_example", NULL);
kfree(buf1);
printk("Goodbye world\n");
}
module_init(init_module_test);
module_exit(cleanup_module_test);
Application code
#include<stdio.h>
#include<stdlib.h>
#include<sys/mman.h>
int main(void)
{
int fd, i;
long long *msg = NULL;
if ((fd = fopen("/proc/mmap_example", "r")) < 0)
{
printf("File not opened");
}
msg = mmap(NULL, 4096, PROT_READ, MAP_SHARED, fd, 0);
if (msg == MAP_FAILED)
{
printf("MAP failed");
return 0;
}
for (i = 0; i < 512; i++)
printf("0x%llx,", msg[i]);
fclose(fd);
return 0;
}
I always end up seing "MAP failed".
Is there something wrong with my code?
The first problem is that you are attempting to use fopen to open a file and placing the return value in an integer, but fopen doesn't return an integer. It returns FILE *. This tells me you are ignoring compiler warnings and errors. That's a bad idea: they're produced for a reason.
The second problem is that you actually do need an integer file handle in order to provide it as an argument to mmap(2). For that, you should be calling open(2) (not fopen(3)).
There may well be additional problems with this code, but that's a start.
well, i can't comment so i post an answer that is not one, but i hope it will be still useful:
i'm not sure about the driver, but you can use the errno method (http://man7.org/linux/man-pages/man3/errno.3.html) on mmap to have a better answer on why it's failing:
add in your application code at the right place:
#include <errno.h>
printf("%i",errno);
or you could maybe use the following if you don't want to print the errno :
cpp -dM /usr/include/errno.h | grep 'define E' | sort -n -k 3
from How to know what the 'errno' means?
debugfs can't handle mmap
I know this is not your exact case, but it also makes mmap fail with MAP_FAILED, and it may help future Googlers: https://patchwork.kernel.org/patch/9252557/
And here is a fully working procfs example with an userland test.

Segmentation fault in linux driver

I'm trying to write a linux driver. The kernel version is 2.4.18 and the distribution is Red Hat linux 8.0.
The code of my driver is:
#define LINUX
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#include <linux/fs.h>
#include <asm-i386/semaphore.h>
#include "rng.h"
#include <linux/random.h>
#include <linux/slab.h>
#define DEVICE_NAME "rng"
#define BUF_LEN 80
static int major;
int init_module();
void cleanup_module();
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
struct file_operations my_fops = {
open: device_open,
release: device_release,
};
/* Init and Cleanup */
int init_module() {
SET_MODULE_OWNER(&my_fops);
major = register_chrdev(0, DEVICE_NAME, &my_fops);
return 0;
}
void cleanup_module() {
int ret = unregister_chrdev(major, DEVICE_NAME);
if (ret < 0)
printk("Error in unregister_chrdev: %d\n", ret);
}
static int device_open(struct inode *inode, struct file *file) {
file->f_op=&my_fops;
return 1;
}
static int device_release(struct inode *inode, struct file *file) {
return 0;
}
And the code I'm using in order to test my driver is:
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int openTest() {
int game1 = open("/dev/game1", O_RDONLY); // SEGMENTATION FAULT
int retValue=1;
close(game1);
return retValue;
}
int main() {
int res;
if (openTest() < 1) {
fprintf(stderr, "open didnt work\n");
return -1;
}
fprintf(stderr, "everything works :)\n");
return 0;
}
In the code above, I'm getting a segmentation fault when I'm trying to open the device. Can somebody explain to me why I'm getting this segmentation fault? I really don't understand.
Thanks a lot!
In Linux kernel land, it is convention to return a 0 (zero) when there are no errors. Your device_open() routine is hardcoded to return a 1 (one), which may be causing your segfault.
This Linux Device Drivers book may be helpful to you. The linked edition is written for kernel 2.0.x - 2.4.x, so the information should be appropriate for the dusty and ancient kernel you are using.
This line seems to be wrong file->f_op=&my_fops;
Basically when writing a linux driver operations are setup at build time itself.

Resources