I want to get the process name from task_struct, but
I get an error dereferencing pointer to incomplete type (task->comm).
I have to use pid_task function.
I have no idea why it does not work.
ssize_t simple_read(struct file *filp, char __user *user_buf, size_t count, loff_t *f_pos) {
int len=0;
pid_struct = find_get_pid(pid);
task = pid_task(pid_struct,PIDTYPE_PID);
len = sprintf(user_buf,"\nname %s\n ",task->comm);
return len;
}
To find the task_struct of a process we can make use of the function pid_task defined in kernel/pid.c .
struct task_struct *pid_task(struct pid *pid, enum pid_type type)
Arguments:
pid : Pointer to the struct pid of the process.
pid_type: PIDTYPE_PID,
PIDTYPE_PGID,
PIDTYPE_SID,
PIDTYPE_MAX
To find the pid structure if we have the pid of a process we can use the functionfind_get_pid which is also defined in kernel/pid.c
struct pid *find_get_pid(pid_t nr)
In the below module we create a read/write proc entry named task_by_pid. Which ever process we want to find the task_struct of using its pid we can write to number into the proc entry.
When we read the proc entry, it will display the name of the process corresponding to the pid we wrote into it.
proc_task_pid:
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/proc_fs.h>
#include <linux/pid.h>
#include <linux/pid_namespace.h>
int p_id;
struct pid *pid_struct;
struct task_struct *task;
static struct proc_dir_entry *proc_write_entry;
char *proc_name="task_by_pid";
int read_proc(char *buf,char **start,off_t offset,int count,int *eof,void *data )
{
int len=0;
pid_struct = find_get_pid(p_id);
task = pid_task(pid_struct,PIDTYPE_PID);
len = sprintf(buf,"\nname %s\n ",task->comm);
return len;
}
int write_proc(struct file *file,const char *buf,int count,void *data )
{
int ret;
char *id;
id = (char *)kmalloc(1000*sizeof(char),GFP_KERNEL);
printk(KERN_INFO "buf passed %s",buf);
if(copy_from_user(id,buf,count))
return -EFAULT;
printk(KERN_INFO "id passed %s",id);
p_id = simple_strtoul(id,NULL,0);
printk(KERN_INFO "pid %d ret %d",p_id,ret);
return sizeof(buf);
}
void create_new_proc_entry()
{
proc_write_entry = create_proc_entry(proc_name,0666,NULL);
if(!proc_write_entry)
{
printk(KERN_INFO "Error creating proc entry");
return -ENOMEM;
}
proc_write_entry->read_proc = read_proc ;
proc_write_entry->write_proc = write_proc;
printk(KERN_INFO "proc initialized");
}
int proc_init (void) {
create_new_proc_entry();
return 0;
}
void proc_cleanup(void) {
printk(KERN_INFO " Inside cleanup_module\n");
remove_proc_entry(proc_name,NULL);
}
MODULE_LICENSE("GPL");
module_init(proc_init);
module_exit(proc_cleanup);
Use the following make file to compile it:
ifneq ($(KERNELRELEASE),)
obj-m := proc_task_pid.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
Compile it using
$make
Insert it into the kernel:
$ insmod proc_task_pid.ko
Now let us try to find the name of the process with pid "1", which is always init.
$ printf "1" > /proc/task_by_pid
$ cat /proc/task_by_pid
name init
As expected the output is "init". Thus we can find the task_struct of any process using its pid.
Source code from here.
Related
I have an assignment, where I have to create a proc_entry which can be written to(by user) and read from(by kernel).
The motive is that the kernel code should be able to read the value in the proc_entry, and use it later as a threshold for number of files opened by a process. If a process has opened more files that this threshold, it will be penalized in the scheduler. As user can also change value inside this proc_entry, thus, kernel will use this threshold dynamically.
Most of the codes I have seen online, tell how to create a module that will create such an entry, and another module that given the path of this entry, will read the string present.
The code for the module to create I/O proc_entry is- (Using the below module, I am able to create a proc_entry "/proc/my_proc_entry_write", to which, I can write using- "echo 200 > /proc/my_proc_entry_write", and read this value via "cat /proc/my_proc_entry_write")-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <asm/types.h>
#define DATA_SIZE 3000000 // We can keep 1024 bytes of data with us.
#define MY_PROC_ENTRY "my_proc_entry_write"
#define PROC_FULL_PATH "/proc/my_proc_entry_write"
struct proc_dir_entry *proc;
int len;
char *msg = NULL;
/*
* Function to write to the proc. Here we free get the new value from buffer,
* count from the buffer and then overwrite the data in our file.
*
* Note that - you can have any other implementation as well for this, all you have to
* ensure that you comply with the expectations of the write() system calls
* like filling in the buffer, and returning the numbers of character written.
*/
static ssize_t my_proc_write(struct file *filp, const char __user * buffer, size_t count, loff_t *pos) // buffer, of length count, should be copied to kernel
{
int i;
char *data = PDE_DATA(file_inode(filp)); // gives data pointer of file
if (count > DATA_SIZE) {
return -EFAULT;
}
printk(KERN_INFO "Printing the data passed. Count is %lu", (size_t) count);
for (i=0; i < count; i++) {
printk(KERN_INFO "Index: %d . Character: %c Ascii: %d", i, buffer[i], buffer[i]);
}
printk(KERN_INFO "Writing to proc");
if (copy_from_user(data, buffer, count)) {
return -EFAULT;
}
data[count-1] = '\0';
printk(KERN_INFO "msg has been set to %s", msg); // Due to kmalloc, msg points to this. So, when we write, msg is changed.
printk(KERN_INFO "Message is: ");
for (i=0; i < count; i++) {
printk(KERN_INFO "\n Index: %d . Character: %c", i, msg[i]);
}
*pos = (int) count; // length written to be copied to pos at end
len = count-1; // len is length of string. count is len+1, to accomodate the \0.
return count;
}
/*
* Function to read the proc entry, here we copy the data from our proc entry
* to the buffer passed.
*/
ssize_t my_proc_read(struct file *filp,char *buf, size_t count, loff_t *offp ) // copy to buf,which is in userspace
{
char* f_path; int i=0; char f_arr[128]; char* f_path_2;
while(i<128)
{
f_arr[i]=0;
i++;
}
f_path=dentry_path_raw(filp->f_path.dentry,f_arr,128);
printk(KERN_ERR"f_path: %s\n",f_path);
i=0;
while(i<128 && f_arr[i]==0)
{
i++;
}
if(i!=128)
{
f_path_2=&f_arr[i];
printk(KERN_ERR"f_path_2: %s\n",f_path_2);
}
int err;
char *data = PDE_DATA(file_inode(filp));
if ((int) (*offp) > len) {
return 0;
}
printk(KERN_INFO "Reading the proc entry, len of the file is %d", len);
if(!(data)) {
printk(KERN_INFO "NULL DATA");
return 0;
}
if (count == 0) {
printk(KERN_INFO "Read of size zero, doing nothing.");
return count;
} else {
printk(KERN_INFO "Read of size %d", (int) count);
}
count = len + 1; // +1 to read the \0 ; thus we store the previous written length in global variable len
err = copy_to_user(buf, data, count); // +1 for \0
printk(KERN_INFO "Read data : %s", buf);
*offp = count;
if (err) {
printk(KERN_INFO "Error in copying data.");
} else {
printk(KERN_INFO "Successfully copied data.");
}
return count;
}
/*
* The file_operations structure. This is the glue layer which associates the
* proc entry to the read and write operations.
*/
struct file_operations proc_fops = {
.read = my_proc_read,
.write = my_proc_write,
};
/*
* This function will create the proc entry. This function will allocate some
* data where the data will be written incase of a write to the proc entry. The
* same memory will be used to serve the reads. * Initially the function fills
* the data with DATA which has "100".
* The important function to see here is the proc_create_data, this function
* will take the proc entry name and create it with the given permissions
* (0666). We also need to pass the file_operations structure which has the
* function pointers to the functions which needs to be called when read or
* write is called on the file.
The last argument has the pointer to the data
* associated with the file. (So, by "char *data = PDE_DATA(file_inode(filp));", the 'data' is actually 'msg')
*/
int create_new_proc_entry(void) {
int i;
char *DATA = "100";
len = strlen(DATA);
msg = kmalloc((size_t) DATA_SIZE, GFP_KERNEL); // +1 for \0
if (msg != NULL) {
printk(KERN_INFO "Allocated memory for msg");
} else {
return -1;
}
strncpy(msg, DATA, len+1);
for (i=0; i < len +1 ; i++) {
printk(KERN_INFO "%c", msg[i]);
if (msg[i] == '\0') {
printk(KERN_INFO "YES");
}
}
proc = proc_create_data(MY_PROC_ENTRY, 0666, NULL, &proc_fops, msg);
if (proc) {
return 0;
}
return -1;
}
/* The init function of the module. Does nothing other than calling the
* create_new_proc_entry. */
int proc_init (void) {
if (create_new_proc_entry()) {
return -1;
}
return 0;
}
/* Function to remove the proc entry. Call this when the module unloads. */
void proc_cleanup(void) {
remove_proc_entry(MY_PROC_ENTRY, NULL);
}
MODULE_LICENSE("GPL");
module_init(proc_init);
module_exit(proc_cleanup);
Makefile for the above module is(assuming the code of module is written in file proc_write_read.c):-
MYPROC=proc_write_read
obj-m += $(MYPROC).o
export KROOT=/lib/modules/$(shell uname -r)/build
#export KROOT=/lib/modules/$(uname)3.2.0-23-generic/build
allofit: modules
modules: clean
#$(MAKE) -C $(KROOT) M=$(PWD) modules
modules_install:
#$(MAKE) -C $(KROOT) M=$(PWD) modules_install
kernel_clean:
#$(MAKE) -C $(KROOT) M=$(PWD) clean
clean: kernel_clean
rm -rf Module.symvers modules.order
insert: modules
dmesg -c
insmod proc_write_read.ko
remove: clean
rmmod proc_write_read
The module that reads this proc_entry, like a file is-
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <asm/types.h>
int proc_init(void)
{
struct file *f; ssize_t ret = -EBADF;int i;
char* f_path;
i=0;
f=NULL;
char buf[128]; char f_arr[128];
mm_segment_t fs;
i=0;
while(i<128)
{
buf[i] = 0;
f_arr[i]=0;
i++;
}
// To see in /var/log/messages that the module is operating
//printk(KERN_INFO "read_file- my module is loaded\n");
f = filp_open("/proc/my_proc_entry_write", O_RDONLY, 0);
if (IS_ERR(f)) {
printk(KERN_ERR "Error in filp_open: %p ; %d\n", f,PTR_ERR(f));
return 100000;
}
f_path=dentry_path_raw(f->f_path.dentry,f_arr,128);
printk(KERN_ERR"f_path_in_proc_entry_read: %s\n",f_path);
printk(KERN_ERR"kernel Below1!!!\n");
// Get current segment descriptor
fs = get_fs();
printk(KERN_ERR"kernel Below2!!!\n");
// Set segment descriptor associated to kernel space
set_fs(get_ds());
printk(KERN_ERR"kernel Below3!!!\n");
// Read the file
if (f!=NULL) {
if ((f->f_op)!=NULL && (f->f_op->read)!=NULL){
ret=f->f_op->read(f, buf, 128, &f->f_pos);
printk(KERN_ERR"kernel Below4!!!\n");
}
else
return 100000;
}
else
return 100000;
// Restore segment descriptor
set_fs(fs);
// See what we read from file
printk(KERN_ERR "kernel Read my_proc_entry_write buf:%s\n",buf);
int val=0;
sscanf(buf, "%d", &val);
printk(KERN_ERR"kernel val: %d\n",val);
filp_close(f,NULL);
return val;
}
void proc_cleanup(void)
{
printk(KERN_INFO "My module is unloaded\n");
}
module_init(proc_init);
module_exit(proc_cleanup);
Makefile for the above module(name=read_file_in_kernel) is-
obj-m += read_file_in_kernel.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
My question is- Both these modules work fine as userspace modules, via insmod, but if I copy-paste this code to the source code of kernel 4.19.200 (not exact copy-paste, just the main parts as functions), and use the 2nd module,i.e, read_file_in_kernel's code to access the proc value, I am getting an error, i.e, kernel is not able to boot.
On running gdb through the kernel, I found that the code in read_file_in_kernel went through the below code, thrice (i.e, when update_curr function in linux kernel called this function 3 times),i.e, f is being returned as an error every time-
if (IS_ERR(f)) {
printk(KERN_ERR "Error in filp_open: %p ; %d\n", f,PTR_ERR(f));
return 100000;
}
In the 4th call to read_file_in_kernel, the kernel froze on -
f = filp_open("/proc/my_proc_entry_write", O_RDONLY, 0);
Same case with gdb.
I don't know what I am doing wrong here. Is it that /proc/my_proc_entry_write is not being created during bootup when it is read, and so, filp_open is not able to open that proc_entry to be read.
I even tried removing the first module from kernel entirely, running it separately from user-space to create a proc_entry(my_proc_entry_write) beforehand, that will be loaded by default every time the kernel boots up. But still, same error is coming.
What correction should I make to this?
If this is not the way to create a dynamic proc_entry that can be written to by user and ready by kernel, what is?
I'm trying to implement character device driver in C at Linux.
My code is as follows:
#include<linux/device.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/err.h>
#include<asm/uaccess.h>
#define SUCCESS 0
#define DEVICE_NAME "chardev"
#define BUF_LEN 80
MODULE_LICENSE("GPL");
static int Major;
static char msg[BUF_LEN]={0};
static short s_o_msg;
static int Device_Open = 0;
static struct class* chardevClass = NULL;
static struct device* chardevDevice = NULL;
static char *msg_Ptr;
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
static int __init chardev_init(void){
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk(KERN_ALERT "Registering char device failed with %d\n", Major);
return Major;
}
chardevDevice = device_create(chardevClass, NULL, MKDEV(Major,0), NULL, DEVICE_NAME);
if (IS_ERR(chardevDevice)) {
class_destroy(chardevClass);
unregister_chrdev(Major, DEVICE_NAME);
printk(KERN_ALERT
"Failed to create the device\n");
return PTR_ERR(chardevDevice);
}
printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
printk(KERN_INFO "the driver, create a dev file with\n");
printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
printk(KERN_INFO "the device file.\n");
printk(KERN_INFO "Remove the device file and module when done.\n");
return SUCCESS;
}
static void __exit chardev_exit(void){
device_destroy(chardevClass, MKDEV(Major, 0));
class_unregister(chardevClass);
class_destroy(chardevClass);
unregister_chrdev(Major, DEVICE_NAME);
printk(KERN_INFO "Goodbye!\n");
}
static int device_open(struct inode *inodep, struct file *filep)
{
static int counter = 0;
if (Device_Open)
return -EBUSY;
Device_Open++;
sprintf(msg, "I already told you %d times Hello world!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static ssize_t device_read(struct file *filep, char *buffer, size_t length, loff_t * offset){
int bytes_read = 0;
if (*msg_Ptr == 0)
return 0;
while (length && *msg_Ptr) {
put_user(*(msg_Ptr++), buffer++);
length--;
bytes_read++;
}
return bytes_read;
}
static int device_release(struct inode *inodep, struct file *filep)
{
Device_Open--;
module_put(THIS_MODULE);
return 0;
}
static ssize_t device_write(struct file *filep, const char *buffer, size_t length, loff_t *offset){
sprintf(msg, "%s(%zu letters)", buffer, length);
s_o_msg = strlen(msg);
printk(KERN_INFO "Received %zu characters from the user\n", length);
return length;
}
module_init(chardev_init);
module_exit(chardev_exit);
then, I compile this with following command and to this moment everything looks just fine:
obj-m := memory.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
but when I tried to run this module with
sudo /sbin/insmod memory.ko
I get an error :
insmod: ERROR: Could not insert module : No such device
Could you explain me please what I'm doing wrong and what should I do to run this module properly?
Thanks a lot.
You forget to create the class( class_create) before device_create() because if you see
root#achal:/sys/class# ls
.. there are so many different class..
your device also should be in one class that's why create one class using class_create();
Add below line in your code.
chardevClass = class_create(THIS_MODULE, "overflow");
chardevDevice = device_create(chardevClass, NULL, MKDEV(Major,0), NULL, DEVICE_NAME);
root mode is required for inserting a module, Sequence for compiling, inserting and running a module are :
First do make
root#root:~/s_flow# make
then do insmod & analyse dmesg output
root#root:~/s_flow# insmod memory.ko
root#root:~/s_flow# dmesg
..
.. check here whether __init chardev_init() is invoked or not
or you can check modinfo also
root#root:~/s_flow# modifno memory.ko
I hope it helps.
I try to use libfuse (cuse) to create character device and play on it like with regular tty, all is fine till I use tcgetattr.
Unfortunately, termios.tcgetattr() always raise I/O error.
cusetest.c
#define FUSE_USE_VERSION 29
#define _FILE_OFFSET_BITS 64
#include <fuse/cuse_lowlevel.h>
#include <fuse/fuse_opt.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//#include <termios.h>
#include <linux/termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#define LOG(...) do { fprintf(stderr, "DEBUG: "__VA_ARGS__); puts(""); } while (0)
static void cusetest_open(fuse_req_t req, struct fuse_file_info *fi) {
LOG("cusetest_open called\n");
fuse_reply_open(req, fi);
}
static void cusetest_read(fuse_req_t req, size_t size, off_t off, struct fuse_file_info *fi) {
LOG("cusetest_read called\n");
fuse_reply_buf(req, "Hello", size > 5 ? 5 : size);
}
static void cusetest_write(fuse_req_t req, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) {
LOG("cusetest_write called, size: %lu bytes\n", size);
fuse_reply_write(req, size);
}
static void cusetest_ioctl(fuse_req_t req, int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz) {
LOG("cusetest_ioctl called, cmd: %d insize: %lu outsize: %lu\n", cmd, in_bufsz, out_bufsz);
struct termios oldtio;
int i;
oldtio.c_iflag = 1;
oldtio.c_oflag = 2;
oldtio.c_cflag = 3;
oldtio.c_lflag = 4;
for (i = 0; i < NCCS; ++i)
{
oldtio.c_cc[i] = i;
}
printf("NCCS:%ud\n\n", NCCS);
printf("c_iflag:%ud \n", oldtio.c_iflag);
printf("c_oflag:%ud\n", oldtio.c_oflag);
printf("c_cflag:%ud\n", oldtio.c_cflag);
printf("c_lflag:%ud\n", oldtio.c_lflag);
// printk("c_ispeed:%ud\n", oldtio.ispeed);
// printk("c_ospeed:%ud\n\n", oldtio.c_ospeed);
for (i = 0; i < NCCS; ++i)
{
printf("CC: %d\n", oldtio.c_cc[i]);
}
printf("\n");
fuse_reply_ioctl(req, 21506, &oldtio, sizeof(oldtio));
}
static const struct cuse_lowlevel_ops cusetest_clop = {
.open = cusetest_open,
.read = cusetest_read,
.write = cusetest_write,
.ioctl = cusetest_ioctl,
};
struct cuse_info2 {
unsigned int dev_major;
unsigned int dev_minor;
unsigned int dev_info_argc;
char ** dev_info_argv;
unsigned int flags;
};
// char * argv[] == char ** argv
int main(int argc, char** argv) {
// -f: run in foreground, -d: debug ouput
// Compile official example and use -h
const char* cusearg[] = {"test", "-f", "-d"};
const char* devarg[] = {"DEVNAME=ttyCUSE0" };
struct cuse_info ci;
memset(&ci, 0x00, sizeof(ci));
ci.flags = CUSE_UNRESTRICTED_IOCTL;
ci.dev_info_argc=1;
ci.dev_info_argv = devarg;
//int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, const struct cuse_lowlevel_ops *clop, void *userdata);
return cuse_lowlevel_main(3, (char**) &cusearg, &ci, &cusetest_clop, NULL);
}
Here I use the same code (structure) in kernel module, and all is fine:
ttymodule.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/termios.h>
#include <linux/errno.h>
#define DEVICE_NAME "ttytest"
#define CLASS_NAME "ttytest"
static int major;
static struct class* tty_class = NULL;
static struct device* tty_device = NULL;
static long fake_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg){
struct termios oldtio;
int i;
oldtio.c_iflag = 1;
oldtio.c_oflag = 2;
oldtio.c_cflag = 3;
oldtio.c_lflag = 4;
for (i = 0; i < NCCS; ++i)
{
oldtio.c_cc[i] = i;
}
printk(KERN_ALERT "ttytest: ioctl called: %d -> %ld \n", cmd_in, arg);
printk(KERN_ALERT "NCCS:%ud\n\n", NCCS);
printk(KERN_ALERT "c_iflag:%ud \n", oldtio.c_iflag);
printk(KERN_ALERT "c_oflag:%ud\n", oldtio.c_oflag);
printk(KERN_ALERT "c_cflag:%ud\n", oldtio.c_cflag);
printk(KERN_ALERT "c_lflag:%ud\n", oldtio.c_lflag);
//printk(KERN_ALERT "c_ispeed:%ud\n", oldtio.ispeed);
//printk(KERN_ALERT "c_ospeed:%ud\n\n", oldtio.c_ospeed);
for (i = 0; i < NCCS; ++i)
{
printk(KERN_ALERT "CC: %d\n", oldtio.c_cc[i]);
}
printk(KERN_ALERT "\n");
return cmd_in+1;
}
static struct file_operations fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = fake_ioctl
};
static int __init tty_init(void){
printk(KERN_INFO "ttytest: Initializing ...\n");
major = register_chrdev(0, DEVICE_NAME, &fops);
if (major<0){
printk(KERN_ALERT "ttytest failed to register a major number\n");
return major;
}
tty_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(tty_class)){
unregister_chrdev(major, DEVICE_NAME);
printk(KERN_ALERT "Failed to register device class\n");
return PTR_ERR(tty_class);
}
tty_device = device_create(tty_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
if (IS_ERR(tty_device)){
class_destroy(tty_class);
unregister_chrdev(major, DEVICE_NAME);
printk(KERN_ALERT "Failed to create the device\n");
return PTR_ERR(tty_device);
}
return 0;
}
static void __exit tty_exit(void){
device_destroy(tty_class, MKDEV(major, 0));
class_unregister(tty_class); // unregister the device class
class_destroy(tty_class); // remove the device class
unregister_chrdev(major, DEVICE_NAME); // unregister the major number
printk(KERN_INFO "ttytest: Goodbye ...\n");
}
module_init(tty_init);
module_exit(tty_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Grzegorz Hetman");
MODULE_DESCRIPTION("A simple tty module to test cuse implementation.");
MODULE_VERSION("0.1");
Makefile:
obj-m := ttymodule.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all: unload clean
$(MAKE) -C $(KERNELDIR) M=$(PWD)
#make load
#make cuse
#sudo ./cusetest
clean:
#rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c *.order *.symvers cusetest
load:
#sudo insmod ttymodule.ko
#sudo chmod 777 /dev/ttytest
#sudo lsmod |grep ttymodule
unload:
#sudo rmmod ttymodule || true
#sudo rm -f /dev/ttymodule
cuse:
#gcc -Wall -g cusetest.c -lfuse -o cusetest
Result(for eg in python):
import termios
termios.tcgetattr(open('/dev/ttyCUSE0','rw+')) # error: (5, 'Input/output error')
termios.tcgetattr(open('/dev/ttytest','rw+')) # [5523920, 0, 1576586344, 32702, 8, 8, ['\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '#', 'r', '\x90', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'g', '\x82', '\x01', '\x00', '\x00', '\x00', '\x00', ',', 'h', 'K', '\x00', '\x00', '\x00', '\x00', '\x00', '\x90']]
As far as I know, cuse drivers aren't like regular tty drivers because they aren't terminal drivers. They are user space character oriented file system drivers.
In order to play with it as you want, it should be under the tty components like below image (Taken from LDD3). Same source as the image describes how to create terminal derivers.
By the way, there is no userspace tty driver I know.
I wrote a linux module to creat a proc file and write and read the data from it. But I am unable to remove the module, its showing an error unable to remove saying "device or resource busy. here is my code.
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/fs.h> /*this is the file structure, file open read close */
#include<linux/cdev.h> /* this is for character device, makes cdev avilable*/
#include<linux/semaphore.h> /* this is for the semaphore*/
#include<linux/uaccess.h> /*this is for copy_user vice vers*/
#include<linux/proc_fs.h>
#define MAX_LEN 1024
int read_info(char *page, char **start, off_t off, int count, int *eof, void *data);
int write_info(struct file *filp, const char __user *buffer, unsigned long length, void *data);
static struct proc_dir_entry *proc_entry;
static char *info;
static int write_index;
static int read_index;
int write_info(struct file *filp, const char __user *buffer, unsigned long length, void *data) {
int capacity = (MAX_LEN - write_index) +1;
if(length > capacity) {
printk(KERN_INFO "NO sapce to write into peoc file \n");
return -1;
}
if(copy_from_user(&info[write_index], buffer, length))
return -2;
write_index += length;
printk(KERN_INFO " megharaj proc writing succesful, %d write \n", length);
return length;
}
int read_info(char *page, char **start, off_t off, int count, int *eof, void *data) {
int len;
len = sprintf(page, "%s\n", &info[read_index]);
read_index += len;
printk(KERN_INFO " megharaj proc reading succesful, %d read \n", len);
return len;
}
int init_module(void)
{
int ret = 0;
info = (char *)vmalloc(MAX_LEN);
memset(info, 0 , MAX_LEN);
/*truct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent);*/
proc_entry = create_proc_entry("megharaj_proc", 0666, NULL);
if(proc_entry == NULL) {
ret = -1;
vfree(info);
printk(KERN_INFO " megharaj proc not created \n");
}
else {
write_index = 0;
read_index = 0;
proc_entry->read_proc = read_info;
proc_entry->write_proc = write_info;
printk(KERN_INFO " megharaj proc created \n");
}
return ret;
}
void clean_module(void)
{
vfree(info);
remove_proc_entry("megharaj_proc", NULL);
}
also attaching the makefile,
obj-m := proc.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD)
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
echo and cat on proc file are working. Once work is done i am not able to remove the module by using sudo rmmod proc
output from lsmod shows
proc 12518 0 [permanent]
Now another question, what is this permanent ? Is this the problem. ?
Either name the module cleanup function cleanup_module (and not clean_module) or specifically declare it as a cleanup function (much better) like so:
module_init(init_module);
module_exit(clean_module);
Trying to compile an example of wrapping library from here
I had to include stdio.h and stdlib.h, and came to that code:
#define _GNU_SOURCE
#define _USE_GNU
#include <signal.h>
#include <execinfo.h>
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
static void show_stackframe() {
void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
trace_size = backtrace(trace, 16);
messages = backtrace_symbols(trace, trace_size);
printf("[bt] Execution path:\n");
for (i=0; i < trace_size; ++i)
printf("[bt] %s\n", messages[i]);
}
int ioctl(int fd, int request, void *data)
{
char *msg;
if (next_ioctl == NULL) {
fprintf(stderr, "ioctl : wrapping ioctl\n");
fflush(stderr);
// next_ioctl = dlsym((void *) -11, /* RTLD_NEXT, */ "ioctl");
next_ioctl = dlsym(RTLD_NEXT, "ioctl");
fprintf(stderr, "next_ioctl = %p\n", next_ioctl);
fflush(stderr);
if ((msg = dlerror()) != NULL) {
fprintf(stderr, "ioctl: dlopen failed : %s\n", msg);
fflush(stderr);
exit(1);
} else
fprintf(stderr, "ioctl: wrapping done\n");
fflush(stderr);
}
if (request == 1) { /* SCSI_IOCTL_SEND_COMMAND ? */
/* call back trace */
fprintf(stderr, "SCSI_IOCTL_SEND_COMMAND ioctl\n");
fflush(stderr);
show_stackframe();
}
return next_ioctl(fd, request, data);
}
and Makefile
#
# Makefile
#
all: libs test_ioctl
libs: libwrap_ioctl.so
libwrap_ioctl.so: wrap_ioctl.c
rm -f libwrap_ioctl.so*
gcc -fPIC -shared -Wl,-soname,libwrap_ioctl.so.1 -ldl -o libwrap_ioctl.so.1.0 wrap_ioctl.c
ln -s libwrap_ioctl.so.1.0 libwrap_ioctl.so.1
ln -s libwrap_ioctl.so.1 libwrap_ioctl.so
clean:
rm -f libwrap_ioctl.so* test_ioctl
and stuck in these errors, despite dlfcn.h is included.
~/my_src/native/glibc_wrapper > make
rm -f libwrap_ioctl.so*
gcc -fPIC -shared -Wl,-soname,libwrap_ioctl.so.1 -ldl -o libwrap_ioctl.so.1.0 wrap_ioctl.c
wrap_ioctl.c: In function ‘ioctl’:
wrap_ioctl.c:26: error: ‘next_ioctl’ undeclared (first use in this function)
wrap_ioctl.c:26: error: (Each undeclared identifier is reported only once
wrap_ioctl.c:26: error: for each function it appears in.)
make: *** [libwrap_ioctl.so] Ошибка 1
dlfcn.h itself doesn't define any symbol with name next_smth. (In SUS, dlfcn.h only defines several dl* functions and RTLD_ macro: http://pubs.opengroup.org/onlinepubs/7908799/xsh/dlfcn.h.html)
You should define this as pointer to function in your program code in explicit way. Something like this: (taken from https://port70.net/svn/misc/remac/remac.c or from https://github.com/itm/forward-sensor/blob/master/preload.c or ... any google search for "next_ioctl"):
static int (*next_ioctl) (int fd, int request, void *data) = NULL;
Or, if you want a collective blog-reading session, there is additional line in the blog post with ioctl overloading: http://scaryreasoner.wordpress.com/2007/11/17/using-ld_preload-libraries-and-glibc-backtrace-function-for-debugging/ (just before first huge code fragment)
Then, declare a function pointer to hold the value
of the “real” ioctl() function from glibc:
static int (*next_ioctl)(int fd, int request, void *data) = NULL;
Then declare your replacement ioctl function:
You missed to declare next_ioctl.
Just add
void * next_ioctl = NULL;
int (*next_ioctl) (int, int, ...) = NULL;
to main().