It can act as a bridge connecting the user space and the kernel space. User space program can use proc files to read the information exported by kernel. Every entry in the proc file system provides some information from the kernel.
The entry “meminfo” gives the details of the memory being used in the system.
To read the data in this entry just run
To read the data in this entry just run
cat /proc/meminfo
Similarly the “modules” entry gives details of all the modules that are currently a part of the kernel.
cat /proc/modules
It gives similar information as lsmod. Like this more proc entries are there.
/proc/devices
— registered character and block major numbers/proc/iomem
— on-system physical RAM and bus device addresses/proc/ioports
— on-system I/O port addresses (especially for x86 systems)/proc/interrupts
— registered interrupt request numbers/proc/softirqs
— registered soft IRQs/proc/swaps
— currently active swaps/proc/kallsyms
— running kernel symbols, including from loaded modules/proc/partitions
— currently connected block devices and their partitions/proc/filesystems
— currently active filesystem drivers/proc/cpuinfo
— information about the CPU(s) on the system
Most proc files are read-only and only expose kernel information to user space programs.
proc files can also be used to control and modify kernel behavior on the fly. The proc files needs to be writtable in this case.
For example, to enable IP forwarding of iptable, one can use the command below,
echo 1 > /proc/sys/net/ipv4/ip_forward
Creating Procfs Entry
The creation of proc entries has undergone a considerable change in kernel version 3.10 and above. In this post we will see one of the methods we can use in linux kernel version 3.10 and above let us see how we can create proc entries in version 3.10 and above.
1
2
3
static inline struct proc_dir_entry *proc_create(const char *name, umode_t mode,
struct proc_dir_entry *parent,
const struct file_operations *proc_fops)
The function is defined in proc_fs.h.
Where,
<name
> : The name of the proc entry
<mode
> : The access mode for proc entry
<parent
> : The name of the parent directory under /proc. If NULL is passed as parent, the /proc directory will be set as parent.
<proc_fops
> : The structure in which the file operations for the proc entry will be created.
#include
#include
#include
#include
#include
#include
#include
#include //kmalloc()
#include //copy_to/from_user()
#include
#include
#define WR_VALUE _IOW('a','a',int32_t*)
#define RD_VALUE _IOR('a','b',int32_t*)
int32_t value = 0;
char etx_array[20]="try_proc_array\n";
static int len = 1;
dev_t dev = 0;
static struct class *dev_class;
static struct cdev etx_cdev;
static int __init etx_driver_init(void);
static void __exit etx_driver_exit(void);
/*************** Driver Fuctions **********************/
static int etx_open(struct inode *inode, struct file *file);
static int etx_release(struct inode *inode, struct file *file);
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len,loff_t * off);
static ssize_t etx_write(struct file *filp, const char *buf, size_t len, loff_t * off);
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/***************** Procfs Functions *******************/
static int open_proc(struct inode *inode, struct file *file);
static int release_proc(struct inode *inode, struct file *file);
static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length,loff_t * offset);
static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t * off);
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = etx_read,
.write = etx_write,
.open = etx_open,
.unlocked_ioctl = etx_ioctl,
.release = etx_release,
};
static struct file_operations proc_fops = {
.open = open_proc,
.read = read_proc,
.write = write_proc,
.release = release_proc
};
static int open_proc(struct inode *inode, struct file *file)
{
printk(KERN_INFO "proc file opend.....\t");
return 0;
}
static int release_proc(struct inode *inode, struct file *file)
{
printk(KERN_INFO "proc file released.....\n");
return 0;
}
static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length,loff_t * offset)
{
printk(KERN_INFO "proc file read.....\n");
if(len)
len=0;
else{
len=1;
return 0;
}
copy_to_user(buffer,etx_array,20);
return length;;
}
static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk(KERN_INFO "proc file wrote.....\n");
copy_from_user(etx_array,buff,len);
return len;
}
static int etx_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device File Opened...!!!\n");
return 0;
}
static int etx_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device File Closed...!!!\n");
return 0;
}
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Readfunction\n");
return 0;
}
static ssize_t etx_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Write Function\n");
return 0;
}
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case WR_VALUE:
copy_from_user(&value ,(int32_t*) arg, sizeof(value));
printk(KERN_INFO "Value = %d\n", value);
break;
case RD_VALUE:
copy_to_user((int32_t*) arg, &value, sizeof(value));
break;
}
return 0;
}
static int __init etx_driver_init(void)
{
/*Allocating Major number*/
if((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) <0){
printk(KERN_INFO "Cannot allocate major number\n");
return -1;
}
printk(KERN_INFO "Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
/*Creating cdev structure*/
cdev_init(&etx_cdev,&fops);
etx_cdev.owner = THIS_MODULE;
etx_cdev.ops = &fops;
/*Adding character device to the system*/
if((cdev_add(&etx_cdev,dev,1)) < 0){
printk(KERN_INFO "Cannot add the device to the system\n");
goto r_class;
}
/*Creating struct class*/
if((dev_class = class_create(THIS_MODULE,"etx_class")) == NULL){
printk(KERN_INFO "Cannot create the struct class\n");
goto r_class;
}
/*Creating device*/
if((device_create(dev_class,NULL,dev,NULL,"etx_device")) == NULL){
printk(KERN_INFO "Cannot create the Device 1\n");
goto r_device;
}
/*Creating Proc entry*/
proc_create("etx_proc",0666,NULL,&proc_fops);
printk(KERN_INFO "Device Driver Insert...Done!!!\n");
return 0;
r_device:
class_destroy(dev_class);
r_class:
unregister_chrdev_region(dev,1);
return -1;
}
void __exit etx_driver_exit(void)
{
remove_proc_entry("etx_proc",NULL);
device_destroy(dev_class,dev);
class_destroy(dev_class);
cdev_del(&etx_cdev);
unregister_chrdev_region(dev, 1);
printk(KERN_INFO "Device Driver Remove...Done!!!\n");
}
module_init(etx_driver_init);
module_exit(etx_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeTronicX " );
MODULE_DESCRIPTION("A simple device driver");
MODULE_VERSION("1.6");
1
2
3
|
static inline struct proc_dir_entry *proc_create(const char *name, umode_t mode,
struct proc_dir_entry *parent,
const struct file_operations *proc_fops)
|
name
> : The name of the proc entry<
mode
> : The access mode for proc entry<
parent
> : The name of the parent directory under /proc. If NULL is passed as parent, the /proc directory will be set as parent.<
proc_fops
> : The structure in which the file operations for the proc entry will be created.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define WR_VALUE _IOW('a','a',int32_t*)
#define RD_VALUE _IOR('a','b',int32_t*)
int32_t value = 0;
char etx_array[20]="try_proc_array\n";
static int len = 1;
dev_t dev = 0;
static struct class *dev_class;
static struct cdev etx_cdev;
static int __init etx_driver_init(void);
static void __exit etx_driver_exit(void);
/*************** Driver Fuctions **********************/
static int etx_open(struct inode *inode, struct file *file);
static int etx_release(struct inode *inode, struct file *file);
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len,loff_t * off);
static ssize_t etx_write(struct file *filp, const char *buf, size_t len, loff_t * off);
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/***************** Procfs Functions *******************/
static int open_proc(struct inode *inode, struct file *file);
static int release_proc(struct inode *inode, struct file *file);
static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length,loff_t * offset);
static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t * off);
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = etx_read,
.write = etx_write,
.open = etx_open,
.unlocked_ioctl = etx_ioctl,
.release = etx_release,
};
static struct file_operations proc_fops = {
.open = open_proc,
.read = read_proc,
.write = write_proc,
.release = release_proc
};
static int open_proc(struct inode *inode, struct file *file)
{
printk(KERN_INFO "proc file opend.....\t");
return 0;
}
static int release_proc(struct inode *inode, struct file *file)
{
printk(KERN_INFO "proc file released.....\n");
return 0;
}
static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length,loff_t * offset)
{
printk(KERN_INFO "proc file read.....\n");
if(len)
len=0;
else{
len=1;
return 0;
}
copy_to_user(buffer,etx_array,20);
return length;;
}
static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk(KERN_INFO "proc file wrote.....\n");
copy_from_user(etx_array,buff,len);
return len;
}
static int etx_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device File Opened...!!!\n");
return 0;
}
static int etx_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device File Closed...!!!\n");
return 0;
}
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Readfunction\n");
return 0;
}
static ssize_t etx_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Write Function\n");
return 0;
}
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case WR_VALUE:
copy_from_user(&value ,(int32_t*) arg, sizeof(value));
printk(KERN_INFO "Value = %d\n", value);
break;
case RD_VALUE:
copy_to_user((int32_t*) arg, &value, sizeof(value));
break;
}
return 0;
}
static int __init etx_driver_init(void)
{
/*Allocating Major number*/
if((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) <0){
printk(KERN_INFO "Cannot allocate major number\n");
return -1;
}
printk(KERN_INFO "Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
/*Creating cdev structure*/
cdev_init(&etx_cdev,&fops);
etx_cdev.owner = THIS_MODULE;
etx_cdev.ops = &fops;
/*Adding character device to the system*/
if((cdev_add(&etx_cdev,dev,1)) < 0){
printk(KERN_INFO "Cannot add the device to the system\n");
goto r_class;
}
/*Creating struct class*/
if((dev_class = class_create(THIS_MODULE,"etx_class")) == NULL){
printk(KERN_INFO "Cannot create the struct class\n");
goto r_class;
}
/*Creating device*/
if((device_create(dev_class,NULL,dev,NULL,"etx_device")) == NULL){
printk(KERN_INFO "Cannot create the Device 1\n");
goto r_device;
}
/*Creating Proc entry*/
proc_create("etx_proc",0666,NULL,&proc_fops);
printk(KERN_INFO "Device Driver Insert...Done!!!\n");
return 0;
r_device:
class_destroy(dev_class);
r_class:
unregister_chrdev_region(dev,1);
return -1;
}
void __exit etx_driver_exit(void)
{
remove_proc_entry("etx_proc",NULL);
device_destroy(dev_class,dev);
class_destroy(dev_class);
cdev_del(&etx_cdev);
unregister_chrdev_region(dev, 1);
printk(KERN_INFO "Device Driver Remove...Done!!!\n");
}
module_init(etx_driver_init);
module_exit(etx_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeTronicX
MODULE_DESCRIPTION("A simple device driver");
MODULE_VERSION("1.6");
|
MakeFile
1
2
3
4
5
6
7
8
9
10
obj-m += driver.o
KDIR = /lib/modules/$(shell uname -r)/build
all:
make -C $(KDIR) M=$(shell pwd) modules
clean:
make -C $(KDIR) M=$(shell pwd) clean
1
2
3
4
5
6
7
8
9
10
|
obj-m += driver.o
KDIR = /lib/modules/$(shell uname -r)/build
all:
make -C $(KDIR) M=$(shell pwd) modules
clean:
make -C $(KDIR) M=$(shell pwd) clean
|
Building and Testing Driver
- Build the driver by using Makefile (
sudo make
)
- Load the driver using
sudo insmod driver.ko
- Check our procfs entry using ls in procfs directory
linux@embetronicx-VirtualBox:ls /proc/
filesystems iomem kallsyms modules partitions
- Now our procfs entry is there under /proc directory.
- Now you can read procfs variable using
cat
.
linux@embetronicx-VirtualBox: cat /proc/etx_proc
try_proc_array
- We initialized the etx_array with “try_proc_array”. That’s why we got “try_proc_array”.
- Now do proc write using
echo
command and check using cat
.
linux@embetronicx-VirtualBox: echo "device driver proc" > /proc/etx_proc
linux@embetronicx-VirtualBox: cat /proc/etx_proc
device driver proc
sudo make
)sudo insmod driver.ko
linux@embetronicx-VirtualBox:ls /proc/
filesystems iomem kallsyms modules partitions
cat
.linux@embetronicx-VirtualBox: cat /proc/etx_proc
try_proc_array
echo
command and check using cat
.linux@embetronicx-VirtualBox: echo "device driver proc" > /proc/etx_proc
linux@embetronicx-VirtualBox: cat /proc/etx_proc
device driver proc
No comments:
Post a Comment