Wojciech Reszelewski
Wojciech Reszelewski

Reputation: 2716

Not everything is sent properly to the user by kernel module

I' ve got such a function

static ssize_t read_mydevice(struct file *filp, char* buf, size_t count, loff_t* ppos) {

 char *text = "Device is empty\n";
    int len = strlen(text);


    if (*ppos != 0)
            return 0;


    if(count>bytesindev) count=bytesindev;
    if(bytesindev==0) {

        if (copy_to_user(buf, text, len))
                 return -EINVAL;
     } else {
        while(count>0) {
        if (copy_to_user(buf++, msg_Ptr, (unsigned long) 1)) {
                 return -EINVAL;
                } else {
                    strcpy(msg_Ptr, (msg_Ptr+1));
                    bytesindev-=1;
                    *(msg_Ptr+bytesindev) = '\0';
                }
                count-=1;
                printk(KERN_INFO "%d\n", count);
            }
            printk(KERN_INFO "%s\n", buf);
     }
    /*
     * Tell the user how much data we wrote.
     */
    *ppos = len;

    return len;

 }

The problem is that user doesn't get whole message, it always is a first 13-16 signs of it, a loop is made so many times that it's supposed to. At first the third argument passed to copy_to_user was the length of whole message, but this solutions also didn't work properly. Any ideas? This function should give the user a part of buffer he demanded (number of bytes first written to the buffer, a bit like a FIFO). Data must have been send earlier to the device. It's the function for writing:

static ssize_t
write_mydevice(struct file *filp, const char *buff, size_t len, loff_t * off)
{
if(bytesindev+len>limit) {
    if(limit-bytesindev<=0) {
        printk(KERN_ALERT "Device is full.\n");
            return -EINVAL;
    } else {
        printk(KERN_INFO "Device almost full.\n");
        strncat(msg_Ptr, buff, limit-bytesindev);
        bytesindev+=limit-bytesindev;
        return limit-bytesindev;
    }
} else {
    //printk(KERN_INFO "Device working\n");
    strncat(msg_Ptr, buff, len);
    bytesindev+=len;
    return len;
} 
}

Upvotes: 0

Views: 128

Answers (2)

Wojciech Reszelewski
Wojciech Reszelewski

Reputation: 2716

The problem was that read function returns wrong value, it always returns length of text, not the lenght of the sended message.

Upvotes: 0

Mark Wilkins
Mark Wilkins

Reputation: 41252

The intent of the code is not completely clear to me, but there is at least one problem. The strcpy call is not valid. It is not guaranteed to work with overlapping buffers:

strcpy(msg_Ptr, (msg_Ptr+1));

It may have the intended result, but it is undefined behavior. See strcpy

Upvotes: 2

Related Questions