about write function in linux device driver - c

I wrote a linux device driver and implemented the function device_write like this:
static int device_write(struct file* file,const char* buff,int count, loff * offp)
{
//some implementation
printk("write value %x to card\n",value);
//some implementation
}
I also implement the device_read function and have a printk to print some information in it.
The problem is when I use the read(fd,buff,1) in application program the printk result is displayed but when I use the write(fd,buff,1) there is no printk's result.The device_write function may not be called.What can cause this problem? Have anyone encounter this kind of problem before? Can anybody give me some help and suggestion?

This is only half an answer, but it is too big for a comment.
Are other actions within your device_write function happening?
Do a very simple printk at the top of the device_write function and see if that prints. Something like
static int device_write(struct file* file,const char* buff,int count, loff * offp)
{
printk("%s: %s\n", __FILE__, __func__);
that executes regardless of whatever else happens in the function. If that prints then you can narrow down where to go from there.
If that doesn't work then make sure you are actually setting the function pointer in the device structure. Or maybe your error is in the test application. Are you sure that you've opened up the device with write permissions? That would be an easy mistake to make if you copied code from a program initially written just to test the read functionality.

Related

Writing to Linux device driver causes infinite loop

I have been writing a kernel space device driver that can be read from and written to from user space. The open, read, release operations all work perfectly. The problem I am having is with the user-space code that should access the device driver and and write something to it.
The user-space program writes to two files: 1) to a .txt file (and prints a to the console to let the user know it was completed), and 2) to the device driver (and also prints a text to let the user know it was also completed).
Below is the user-space code in full:
int main() {
FILE *fp;
fp = fopen("./test.txt","w");
fputs("Test\n", fp);
fclose(fp);
printf("Printed to txt\n"); //Prints normally.
fp = fopen("/dev/testchar", "w");
fputs("Test\n", fp);
fclose(fp);
printf("Printed to dev\n"); //Never gets to this point
return 0;
}
When I compile and run the code the program spits out
Printed to txt
and just hangs until ctrl+c is called. It never gets beyond the second fputs().
While monitoring kern.log I see endless calls to write to the device driver.
Here I have extracted relevant code from the device driver:
static char msg[256] = {0};
static struct file_operations fops =
{
.write = dev_write
};
static ssize_t dev_write(struct file *file, const char *buf, size_t len, loff_t *ppos)
{
sprintf(msg, "Input:%s, Chars:%lu\n", buf, len);
printk(KERN_NOTICE "%s\n", msg);
return 0;
}
uname -r: 4.10.0-38-generic
gcc -v: gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)
My question is: why is the program getting stuck in an infinite loop when writing to the device, and how do I fix it?
Thanks in advance. Any help will be greatly appreciated.
I think the kernel write operation is supposed to return the number of bytes written. You return 0. So the write system call returns to userspace with 0. However, since your userspace code is using stdio, then your userspace code tries the write again, assuming the system call simply didn't write out all the data. If you return the length of the input, then stdio will know all the data was written. Alternatively you can use the write system call directly rather than fputs. Your kernel code will still be incorrect, but your program will terminate.
You can test this using strace and see all the system calls.

Write to file in Kernel Module - have fd, have pointer to write sys call

I know there have been questions like this before, but I'm hoping that I can get some help. As an academic exercise, I'm trying to write to a file from a kernel module. I have saved the original write call from the system call table to a typedef (sys_write_orig) and have replaced it with my own function. That all works fine.
In my new sys_write function, if I use sys_write_orig with the original buffer passed in from userland - it works fine. But when I try to create a new buffer - the issues begin. I understand the separation of kernel memory and user memory - but I thought there was a way to do all this. Any ideas? Here's kind of what I'm trying to do:
char* kernbuf = "foo";
char __user* userbuf = (char*) kmalloc(3*sizeof(char), GFP_USER);
int n = copy_to_user(userbuf,kernbuf,3);
printk("%d bytes copied to user space (I think).\n",n);
n = sys_write_orig(fd,userbuf,3);
printk("%d is the result from the write.\n",n);
I'm kind of new to kernel-land. So any help is appreciated. Thanks!
I think this does it. I did not want to use VFS because I have a pointer to the sys_write function (I hooked it with my own function and saved the original), so I might as well use it. But either way - I sill needed to get kernel space data into user space. This seems to do the trick. Thanks for pointing me back to the VFS post - it had the info that got me to this solution.
void append_file(unsigned int fd)
{
// http://www.linuxjournal.com/node/8110/print
mm_segment_t old_fs;
old_fs = get_fs();
set_fs(KERNEL_DS);
sys_write_orig(fd, (char*)APPEND_TEXT, strlen(APPEND_TEXT));
set_fs(old_fs);
printk(KERN_INFO "Appended \"%s\" to fd:%d.\n", APPEND_TEXT, fd);
}

Is this right? (Read in file in C)

For my assignment I have to create a program similar to the -wc unix command which counts words, lines, etc.
I have to read in flags and read in a text file.
I've set up all the flags and now I'm trying to read in a text file. I don't think I'm doing this right.
void readInFile(char** argv, int arg)
{
FILE *myFile;
char c;
myFile = fopen(argv[arg], "r");
if(!myfile)
{
printf("%s not found!", argv[arg]);
exit(EXIT_FAILURE);
}
}
in my main I call the function readInFile() and pass 2 arguments. Argv and the element where the file should be. So assume this to be correct.
I need help with actually opening up the file. I feel like my fopen() is wrong. I'm new to reading/writing files in C. Thanks alot!
I'm going to give you some general advice here.
Usually functions should do a single job. In this case, you are writing a function to read in a single file. So, don't pass a pointer to all the command-line arguments; pass in a single read-only pointer to the name of the file to open. Then in main() select the correct argument and pass that as the argument.
void readInFile(char const *filename)
Now, if this function will be reading in the file and doing nothing else, it needs to return the data somehow. But if this function will be doing the equivalent of wc, maybe it will read the file and print stuff, not return any data to the main() function. Then maybe the name should be improved:
void wordcount(char const *filename)
The actual call to fopen() looks fine to me.
You check for error, and then call exit() immediately. That's one way to do it. Another way to do it is to return an error code from your function, and have the caller (the main() function) check for failure, and handle the error there.
int wordcount(char const *filename)
{
// ... do stuff
if (failed)
return 1; // return nonzero error code on failure
// ... do more stuff
return 0; // success code
}
int main(int argc, char const **argv)
{
char const *filename;
int result;
filename = argv[1];
result = wordcount(filename);
if (result)
{
fprintf(stderr, "unable to open file '%s'\n", filename, result);
exit(result);
}
return 0;
}
For a program this simple, it doesn't matter much. But once you start building larger systems in software, you will be happier if your functions work well together, and part of that is making functions that return error codes rather than terminating your whole program on any error.
Why am I using 0 for the success code, and non-zero for failure? It's a common way to do it. It's easy to test for non-zero, like if (result) and there are many non-zero codes but only one zero, so you can return many different kinds of errors, but there is only one value needed for "success".
Note that instead of calling exit() from main(), you can just use the return statement. When you return 0 from main(), that signals success, and a non-zero value indicates an error. So you could just use return result; from main() if you like.
In my dummy code, I'm just returning 1 as the error code. But actually, when you call fopen() it returns an error code to you, in a global variable called errno. Probably a better option is to make your function return the actual error code as specified in errno. You could even modify the print statement in the main() function print the errno code, or use the strerror() function to turn that error code into a human-readable message.
Your call to fopen is correct, assuming that argv[arg] is a valid string which refers to a file that exists on the filesystem.
There is a small typo in the program snippet. if(!myfile) should prpbably be if(!myFile). With this change, I presume the code should work. Can you please elaborate the error faced by you?
P.S: I tried your program and it seems to work!

module_init not showing the printk that I want it to

I am trying to make my module display a printk. I'm new to this so I might have some programming errors. This is my module C file:
#include <linux/linkage.h>
#include <linux/time.h>
#include <linux/module.h>
asmlinkage long sys_mycall(int myid, char* firstname)
{
printk ("Hello, %s! \n sys_mycall called from process %d with ID %d. \n",
firstname, current->id, myid);
return 0;
}
static int my_init(void)
{
return 0;
}
static int my_exit(void)
{
printk("Goodbye!");
return 0;
}
module_init(sys_mycall);
module_exit(my_exit);
First thing is that I don't know how the arrow pointer exactly works so I usually omit it from the printk so it compiles perfectly. If someone can give me a link or something on how to understand it I would really appreciate it.
When I insert it using insmod in the terminal and then display the message using dmesg I get the message by the module_init calling the sys_mycall but I cannot add any arguments to it and it displays the message but it doesn't show anything for firstname or for myid.
I think the problem that module init expect no parameters in the function, it must be void (you can add them in a different way), so basically your function is called with garbage that is currently in the stack, which might be anything but it probably zero as otherwise your kernel will crash.
what do you want to print? I understand current->id, but no the others.
You have no log level specified, so I suspect it's being filtered out as below the threshold. Stick a KERN_WARNING in front of your format string and verify that it prints. Message without a log level are interpreted at CONFIG_DEFAULT_MESSAGE_LOGLEVEL from your .config file.

How can I write commands to the vxworks shell with a c program

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).

Resources