I'm supposed to change a configuration parameter of the kernel by using a kernel module. The kernel module should create a proc file and then I should be able to change the parameter by using the cat command, e.g. cat "foobar" > /proc/prompt is supposed to set the parameter to "foobar", where prompt is the name of the proc file that was created in the module.
Furthermore I should be able to initialize the parameter by passing it as an argument when calling the module.
These two articles were basically the only relevant sources that I have found:
http://www.tldp.org/LDP/lkmpg/2.6/html/x769.html for writing to a proc file and http://www.tldp.org/LDP/lkmpg/2.6/html/x323.html for initializing the parameter from the command line.
Now I have a couple of questions, first of all this is the module thus far:
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include "sar_main.h"
#define PROCFS_NAME "sarlkm"
char procfs_buffer[PROCFS_MAX_SIZE];
static unsigned long procfs_buffer_size = 0
struct proc_dir_entry *proc_file_entry;
int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data){
int ret;
printk(KERN_INFO "procfile_read (/proc/%s) aufgerufen \n", PROCFS_NAME);
if (offset > 0){
ret = 0;
}
else{
memcpy(buffer, procfs_buffer, procfs_buffer_size);
ret = procfs_buffer_size;
}
return ret;
}
int procfile_write(struct file *file, const char *buffer, unsigned long count, void *data){
procfs_buffer_size = count;
if (procfs_buffer_size > PROCFS_MAX_SIZE){
procfs_buffer_size = PROCFS_MAX_SIZE;
}
if ( copy_from_user(procfs_buffer, buffer, procfs_buffer)){
return -EFAULT;
}
return procfs_buffer_size;
}
static int __init sar_init(void)
{
prompt_proc = create_proc_entry(PROCFS_NAME, 0644, NULL);
if (prompt_proc = NULL){
remove_proc_entry(PROCFS_NAME, &proc_root);
printk(KERN_ALERT "Error: Konnte proc file nicht kreieren")
return -ENOMEM;
}
prompt_proc->read_proc = procfile_read;
prompt_proc->write_proc = procfile_write;
printk(KERN_INFO "proc/%s wurde erfolgreich kreiert", PROCFS_NAME);
return 0;
}
static void __exit sar_cleanup(void)
{
remove_proc_entry(PROCFS_NAME, &proc_root);
printk(KERN_INFO "proc/%s gelöscht", PROCFS_NAME);
}
module_init(sar_init);
module_exit(sar_cleanup);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
I think I should say that I don't really understand why the read and write functions are supposed to work when using the cat command.
My main question is where exactly is the configuration parameter stored in the proc file? If I would write "foobar" to the proc file using cat and then use cat proc/prompt to read the parameter, how does the read function actually get the new value of the parameter, i.e. where is "foobar" stored in the procfile?
If I would try to initialize the parameter using a command line argument I would have to use a global variable in which to store the value of the parameter, but then how could I use that global variable in the read function, so that cat proc/prompt actually gives out the value that was given to the module from the command line?
The cat command internally calls the read() system call to read data from a file (see man strace).
read() passes the arguments to the VFS and the VFS finally calls your custom procfile_read() routine with the passed arguments (and some additional ones passed by the VFS code). If you want to know more about this, look at the fs directory in kernel sources, especially file read_write.c.
Your particular reading function copies, if some conditions are met, the parameter value (which is stored in procfs_buffer to answer one of your questions) into the user-supplied buffer allocated by cat, which is called buffer in your particular code. It is the same one as passed by the read() system call like in:
read(proc_fd, userspace_buf, 10); /* userspace_buf is buffer! */
Error checking omitted for clearness's sake.
To pass the value to the proc file you have two options:
Use module_param() and write it to your buffer; can only be done once because the module is only loadable once (or unload/reload it every time you want to change the parameter but that sounds inconvenient)
Invoke write() from userspace (like in cat) and modify the buffer as often as you want to (this is currently used by your code)
BTW, I really think your reading function should check the pointer to the user data, i.e. use copy_to_user(), not memcpy().
For further information, read Linux Device Drivers. There's only an old edition available at the moment but an updated one is being written.
you can treat xxx_write or xxx_read in driver just as a interface implement,
when you call write or read in user space,
the kernel will invoke xxx_write or xxx_read in kernel space.
so you need to store it yourself when write call,
and fetch them back when read call,
in xxx_write xxx_read
Related
I am trying to write a simple device driver. The driver has only read/write operations. Ideally, I would like the read() function to work in such a way that when the device file is read from, a message is printed to terminal along with a count of how many times the device file was read from. The driver contains the following libraries and global variables:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/poll.h>
#include <linux/cdev.h>
#include "my_driver.h"
#define DEVICE_NAME "Edev"
#define SUCCESS 0
#define FAILURE -1
#define BUF_LEN 1024
static struct class * cls;
static int major_num;
static int counter=0;
static char message_buffer[BUF_LEN];
static char * message_pointer;
static char * write_pointer;
static struct file_operations elliott_fops = {
.read=device_read,
.write=device_write,
.owner=THIS_MODULE
};
The read function is written like so:
static ssize_t device_read(struct file * filp2, char *buffer2, size_t length2, loff_t *offset2){
ssize_t bytes_in_message=0;
sprintf(message_buffer,"Yes,you read from the driver this many times: %d",counter++);
message_pointer=message_buffer;
while (length2 && *message_pointer++){
put_user(*(message_pointer++),buffer2++);
bytes_in_message++;
length2--;
}
pr_info("Read %lu bytes with %lu bytes remaining in the buffer",bytes_in_message,length2);
return bytes_in_message;
}
What I would like the read() function to do is print the message out to the terminal using the sprint() call, and then the while loop will obtain the message's byte length. The message byte length information as well as the remaining buffer size will then be logged within the kernel
The write function is written like this:
static ssize_t device_write(struct file * filp, const char *buffer, size_t length, loff_t *offset){
ssize_t bytes_read_in=0;
while (length && *buffer++){
get_user(*(write_pointer++),buffer++);
bytes_read_in++;
}
pr_info("The device had %lu bytes written to it",bytes_read_in);
pr_info("Got message from user: %s",write_pointer);
return bytes_read_in;
}
Ideally, if someone performed a write to the device with a "echo "hello linux kernel" > /dev/Edev" command, the message that was written to the device file would be printed in the kernel, as well as how long the message was. However, the read() and write() functions are not behaving like this at all. If, for instance, I load the module and write to the device file, no message have been logged in the kernel. If I then performed a cat /dev/Edev command, what is printed to terminal output is not the message with the count, but rather what was just written to the device with echo.
I am assuming this may have something to do with buffers overwriting each other, but I am confused as the buffer in write is userspace, while the buffer in read is in kernel space. I also am unsure why no messages are being logged to the kernel.
to copy a block of data into userspace for ref (https://www.cs.bham.ac.uk/~exr/teaching/lectures/opsys/13_14/docs/kernelAPI/r4037.html)
use copy_to_user function.
There is too much use of the post-increment operator in the loop in device_read():
while (length2 && *message_pointer++){
put_user(*(message_pointer++),buffer2++);
bytes_in_message++;
length2--;
}
message_pointer has been incremented twice per iteration. Similarly, in device_write():
while (length && *buffer++){
get_user(*(write_pointer++),buffer++);
bytes_read_in++;
}
buffer has been incremented twice per iteration. Also the length variable is not being decremented and the write_pointer variable has not been set.
The modified loops can be as follows. In device_read():
while (length2 && *message_pointer){
put_user(*message_pointer, buffer2);
message_pointer++;
buffer2++;
bytes_in_message++;
length2--;
}
And in device_write():
while (length && *buffer){
get_user(*write_pointer,buffer);
write_pointer++;
buffer++;
bytes_read_in++;
length--;
}
The write_pointer variable still needs to be set to point to a valid buffer in device_write().
[EDIT: Removed paragraph about put_user() and get_user() evaluating their arguments more than once, as I do not think that is the case.]
Hi I have a class assignment that requires me to intercept an open call then read the file and edit the output without editing the file itself this is all done in a loadable module in the kernel space. When I say editing I mean like changing the word she to _he replacing the s with an underscore it changes every instance of the word she to _he well that's the desired result. I have looked online for days trying to figure this out I thought I found a suitable example but it kept giving me an error. As soon as I enter the module into the kernel it instantly says killed then it says I cannot remove it because it is in use when it isn't this forces me to restart my virtual machine. Below is the code. Any help would be appreciated thank you.
#include <linux/module.h> // Needed by all modules
#include <linux/kernel.h> // Needed for KERN_INFO
#include <linux/fs.h> // Needed by filp
#include <asm/uaccess.h> // Needed by segment descriptors
int init_module(void)
{
// Create variables
struct file *f;
char buf[128];
mm_segment_t fs;
int i;
// 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
printk(KERN_INFO "My module is loaded\n");
// 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/fedora-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");
}
module_init(init_module);
module_exit(cleanup_module);
Regarding reading and writing to a file from the kernel, I would suggest that you will read the following article and look into the code snippests in it:
Driving Me Nuts - Things You Never Should Do in the Kernel
Linux Journal 2005, Greg Kroah-Hartman
http://m.linuxjournal.com/article/8110
I 'm trying to get the hostname of my school mac os. I can't use gethostname() as it's in section 3 of the man pages of my school macs, instead of section 2. Is there another way of getting the hostname, without using gethostname()? I'm only allowed to use libc functions in man 2 section.
gethostname is just a sysctl, and sysctl is just a syscall.
And syscalls are (per definition) in section 2 of the manual.
So grab your favourite disassembler (or otool -tV if you have none), nm the libraries in /usr/lib/system to find out which ones export _gethostname and _sysctl, and get to work (or look up the source :P).
Below I re-implemented gethostname using sysctl, and sysctl using syscall:
#include <sys/syscall.h> // SYS_sysctl
#include <sys/sysctl.h> // CTL_KERN, KERN_HOSTNAME
#include <unistd.h> // syscall
int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
{
return syscall(SYS_sysctl, name, namelen, oldp, oldlenp, newp, newlen);
}
int gethostname(char *buf, size_t buflen)
{
int name[] = { CTL_KERN, KERN_HOSTNAME };
size_t namelen = 2;
return sysctl(name, namelen, buf, &buflen, NULL, 0);
}
int puts(const char *s)
{
// left as an exercise to the reader ;)
}
int main(void)
{
#define BUFSIZE 256
char buf[BUFSIZE];
size_t buflen = BUFSIZE;
if(gethostname(buf, buflen) == 0)
{
puts(buf);
}
return 0;
}
The implementation of sysctl isn't too complicated; you really just slap SYS_sysctl (from sys/syscall.h) in front of the other arguments and pass them all on to syscall.
To understand the implementation of gethostname, you have to know how sysctl works:
oldp is where the queried value will be stored.
newp is where the new value will be read from. Since we're not setting any new value, this is NULL here.
name is more or less the actual list of arguments to sysctl, and its contents depend on the actual sysctl being queried.
CTL_KERN denotes that we want something from the kernel.
KERN_HOSTNAME denotes that we'd like to retrieve the hostname.
And since KERN_HOSTNAME doesn't take any arguments, that's all there is to it.
Just for demonstration, had you called KERN_PROCARGS, name would require an additional argument, namely the process ID of which the arguments should be retrieved.
In that case, name would look like this:
int name[] = { CTL_KERN, KERN_PROCARGS, pid };
and namelen would have to be set to 3 accordingly.
Now in the above implementation I've made use of puts, which you're obviously not allowed to do, but I trust you can figure out how to re-implement strlen and use the write syscall with that. ;)
I'd like to share a variable between kernel and user space and I've found that it's possible with procfs.
The kernel module must act in certain way if given value is set. The user space program is responsible for changing this value, but the kernel module must read it when necessary.
I know that I must create the /proc file in the kernel module.
My question is, how to read the file from the kernel module?
Source : linux.die.net/lkmpg/x769.html
/**
* This function is called with the /proc file is written
*
*/
int procfile_write(struct file *file, const char *buffer, unsigned long count,
void *data)
{
/* get buffer size */
procfs_buffer_size = count;
if (procfs_buffer_size > PROCFS_MAX_SIZE ) {
procfs_buffer_size = PROCFS_MAX_SIZE;
}
/* write data to the buffer */
if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) ) {
return -EFAULT;
}
return procfs_buffer_size;
}
To clarify, in Your module whenever user writes to Your file in procfs, this example shows how to handle such write.
In kernel >= 3.10 proc_write is moved to structure file_operations where declaration of write is different, so in newest your solution won't work.
You can implement typical file_operations.write(struct file *, const char __user *, size_t, loff_t *) and reference this to:
struct proc_dir_entry your_proc_dir_entry{
.proc_fops = &your_fops,
}
If I wanted to run a shell command in linux with a c program, I would use
system("ls");
Is there a way I can accomplish this in Wind River vxworks?
I found the below example but I'm wondering do I need to include vxworks header files for this to work? I assume I do, but how do I figure out which one?
Example:
// This function runs a shell command and captures the output to the
// specified file
//
extern int consoleFd;
typedef unsigned int (*UINTFUNCPTR) ();
extern "C" int shellToFile(char * shellCmd, char * outputFile)
{
int rtn;
int STDFd;
int outFileFd;
outFileFd = creat( outputFile, O_RDWR);
printf("creat returned %x as a file desc\n",outFileFd);
if (outFileFd != -1)
{
STDFd=ioGlobalStdGet(STD_OUT);
ioGlobalStdSet(STD_OUT,outFileFd);
rtn=execute(shellCmd);
if (rtn !=0)
printf("execute returned %d \n",outFileFd);
ioGlobalStdSet(STD_OUT,STDFd);
}
close(outFileFd);
return (rtn);
}
I found the code segment below worked for me. For some reason changing the globalStdOut didn't work. Also the execute function did not work for me. But my setting the specific task out to my file, I was able to obtain the data I needed.
/* This function directs the output from the devs command into a new file*/
int devsToFile(const char * outputFile)
{
int stdTaskFd;
int outputFileFd;
outputFileFd = creat( outputFile, O_RDWR);
if (outputFileFd != ERROR)
{
stdTaskFd = ioTaskStdGet(0,1);
ioTaskStdSet(0,1,outputFileFd);
devs();
ioTaskStdSet(0,1,stdTaskFd);
close(outputFileFd);
return (OK);
}
else
return (ERROR);
}
If this is a target/kernel shell (i.e. running on the target itself), then remember that all the shell commands are simply translated to function calls.
Thus "ls" really is a call to ls(), which I believe is declared in dirLib.h
I think that the ExecCmd function is what you are looking for.
http://www.dholloway.com/vxworks/6.5/man/cat2/ExecCmd.shtml
As ever, read the documentation. ioLib.h is required for most of the functions used in that example, and stdio.h of course for printf().
As to the general question of whether you need to include any particular headers for any code to compile, you do need to declare all symbols used, and generally that means including appropriate headers. The compiler will soon tell you about any undefined symbols, either by warning or error (in C89/90 undefined functions are not an error, just a bad idea).