0

Hello,
I'm trying to write a linux module that can be able to read a file line by line and stock each line in a corresponding column of an array. For example if my file contains those following lines:
1
10
20
,I would like to read this file with kernel functions like kernel_read(...) and insert each line in one corresponding column of my array such as tab[0] = 1, tab[1] = 10 and tab[2] = 20; When tab[3] is the array to receive the file's content.

I have already this code but I get the content of line character by character no all the line at same time.

#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>

MODULE_LICENSE("GPL");

char *tab; //the table to contain each line the file
char tmp[10];
static int i=0;
static void read_file(char *filename)
{
  struct file *f = NULL;
  int fd;
  char buf[1]; 
  loff_t f_pos = 0;
  mm_segment_t old_fs = get_fs();
   tab =  kmalloc(15, GFP_KERNEL);
  set_fs(KERNEL_DS);

  f = filp_open(filename, O_RDONLY, 0);
  if (!IS_ERR(f)) {
    printk(KERN_DEBUG);
 while (kernel_read(f, buf, 1, &f_pos) == 1){
      printk("%c", buf[0]);  
      if(buf[0]!='\n'){
      tab[i]=buf[0];
      printk("tab[%d] = %c", i, tab[i]);
      i++;
      }
    }
printk("\n");
    //sys_close(fd);
    filp_close(f, NULL);
  }
  set_fs(old_fs);
}
static int __init init(void)
{
  read_file("myfile.txt");
  return 0;
}

static void __exit exit(void)
{ }

module_init(init);
module_exit(exit);

The above code give me character by character on each line. For example if the value of the line is 10, I can not get 10 but 1 and after 0;

I can do it with C language standard functions in user space.

As it is no able to use them in kernel space, How can I do to be able to insert the content of each lines in columns of the receiving array?

Can help me, please ?

I already know that reading file from kernel is not recommended but I need to do this for some tests.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
Enock
  • 11
  • 1
  • 6
  • 1
    "For example if the value of the line is 10, I can not get 10 but 1 and after 0;" - *Value* of the line is `"10"` - it is a **string**, not an **integer**. You are probably looking a way to convert this string into the integer. For that see question: https://stackoverflow.com/questions/6139493/how-convert-a-char-string-to-int-in-the-linux-kernel. – Tsyvarev Apr 09 '21 at 09:18
  • "A way" would most likely include `strtol` https://pubs.opengroup.org/onlinepubs/009604599/functions/strtol.html – Jona Engel Apr 09 '21 at 09:23
  • 1
    @2419: The question is about Linux **kernel module**, where function `strtol` is not accessible. – Tsyvarev Apr 09 '21 at 10:12
  • @2419 The kernel does have `kstrtol`and other `kstrto...` functions defined in `` though. – Ian Abbott Apr 09 '21 at 15:45
  • @Tsyvarev, What I need in a first time is to get the whole string before converting. Because I curently get one by one character of string "10" (I.e 1 and after 0). I look for a way to get the whole string before converting into integer. In other words, I want to get the string "10" in the buffer (buf) at the same time, not "1" in buf and after "0" in buf. I will read how ```strtol``` work to see if It can do that. – Enock Apr 09 '21 at 15:46
  • Your definition of `tab` variable - `char *tab` - is suitable either for **array of chars/integers**, or for a **single string**. It is NOT suitable for the **array of strings**, as you describe in the question post. You ask what Linux kernel functionality could you use, but it is unclear what do you want to achieve. How do you want to **store** an array of strings which you read from the file? – Tsyvarev Apr 09 '21 at 16:01
  • @Enock: At minimum, consider writing your kernel module as a character device driver, so that an userspace application (or even just `cat file > /dev/yourdev`) provides the data to the driver. You can find lots of examples on the web (including LDD3) by looking for *"Linux character device driver"*. – Glärbo Apr 09 '21 at 16:08
  • 1
    Why are you not reading and parsing the file in userspace and passing the result to the kernel in a simple procfs write? – stark Apr 09 '21 at 18:05
  • @stark, I don't know how to do that. Can you show me an example, please? – Enock Apr 09 '21 at 19:29
  • @Tsyvarev , I have some integer values stored in a file line by line. I just want to read the file and store those line in an array and my module will use column (array[0], array[1], array[2]) of array to do some operations. Is it a way to get whole a line in a file and store it in char, int array in kernel space? If yes, can you just show me how you can do that, please? – Enock Apr 09 '21 at 19:40
  • "Is it a way to get whole a line in a file and store it in char, int array in kernel space?" - Your loop `while (kernel_read(f, buf, 1, &f_pos) == 1)` reads the file char by char, and your condition `if(buf[0]!='\n')` checks that current line is not ended. You correctly store every character you read into `tab` variable. BTW, you even describe that in the question post: "The above code give me character by character on each line.". So, if the first line contains string "10", then your `tab` variable would contain characters "1" and "0". I don't understand your problem. – Tsyvarev Apr 09 '21 at 20:09
  • "What I need is to get whole the line not just one charater." - Eh? A line is a **sequence of characters**. And your `tab` variable contains exactly the sequence of characters. – Tsyvarev Apr 09 '21 at 23:35
  • @Tsyvarev, What I need is to get whole the characters in a line one time, no character by character as my code does.Can you show me how to modify my loop to read all the characters in a line only one ?What I need to modify in above code ? – Enock Apr 09 '21 at 23:36
  • So you are looking for a kernel function, like `getline` in user space, which would replace your `while()` loop, am I correctly understand your problem? Well, there is no ready-made function, which would read a complete line from the file. You may read more than 1 byte using `kernel_read` function and then look for a newline character in the buffer. This is actually the way how `getline` works. – Tsyvarev Apr 09 '21 at 23:42
  • @Tsyvarev, I don’t know why you don’t understand what I want. A line is a sequence of character, I agry with you. But here my code gives me tab[0]=1 and tab[1]=0 if my line is "10". That is what my code does. But what I ask you is how to modify my code to have tab[0]=10. – Enock Apr 09 '21 at 23:46
  • 1
    10 is an **integer** and it is a result of the **conversion** from the **string** "10", which is stored in the file, into the **integer**. In the [my first comment](https://stackoverflow.com/questions/67014872/read-file-line-by-line-in-an-array-for-linux-kernel-module?noredirect=1#comment118462269_67014872) I asked you whether you are looking for a string conversion into integer, but you have answered negatively: "I look for a way to get the whole string before converting into integer." – Tsyvarev Apr 09 '21 at 23:50
  • Yes, you understood now. So, if I do ”’kernel_read(f,buf, 2,&f_pos)”’ I will read two characters ? and so for? – Enock Apr 09 '21 at 23:53
  • @Tsyvarev, `const char *` is enough to keep strings of a dynamic length, or, if you know the fixed length that applicable to each of the strings, you may also iterate over them. – 0andriy Apr 10 '21 at 12:17
  • I added +1 to the @stark 's comment. Do parsing in the user space and supply your data via debugfs / sysfs / etc. – 0andriy Apr 10 '21 at 12:21
  • "So, if I do `kernel_read(f,buf, 2,&f_pos)` I will read two characters ? and so for?" - After that you may append the null character to your stored string (so the string will become *null-terminating* string) and **convert** this string into integer using, for example, [kstrtoint](https://elixir.bootlin.com/linux/v5.11.12/source/lib/kstrtox.c#L244). – Tsyvarev Apr 10 '21 at 13:16
  • OK guys, I will try and come back to you. Regards – Enock Apr 11 '21 at 13:44
  • Hello Guys, I did what you advised me to do. I was able to use kstrtol to convert the characters in the lines of my file to numbers (Integer). Thank you to all of you ! However, I have another question. When I read a small file (less than 915 lines) reading is fine but when the number of lines in the file is more than 915 lines I have this message : ```BUG: unable to handle kernel paging request at ffffffffc0857000 [ 4035.244011] IP: init+0xf3/0x1000 [open_4] ``` Anyone know the meaning of this BUG and how to fix it please? – Enock Apr 20 '21 at 14:22
  • I believe you are talking about the file bigger than 4096 bytes and line number doesn’t make any difference. People already told you how you should do: parse your file in user space and supply via one of the virtual file systems available in the kernel (_sysfs_, _debugfs_, ...). Another way is to use `request_firmware()` API. – 0andriy Apr 24 '21 at 09:04
  • @0andriy, thank you. I agree with you but I don't how to do it. Can you give me an example or a link to show me how to it, please ? In second time if you know how to increase the limit of 4096 bytes in the kernel side, tell me please. – Enock Apr 26 '21 at 07:44
  • I know, but it's completely wrong direction. Try to find information yourself. It's your home work at the end, not ours. – 0andriy Apr 26 '21 at 13:19
  • @0andriy, Thank you but you must notice that I never asked you to do my home work for me. What I said you is very clear. I just asked you to give me an example or a link to show me how to do it. – Enock Apr 26 '21 at 17:14

0 Answers0