Advertisement
bueddl

linux kernel: procfs demo-handling multiple proc files with

Aug 10th, 2015
257
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.34 KB | None | 0 0
  1. /* Required for all modules */
  2. #include "linux/init.h"
  3. #include "linux/module.h"
  4. #include "linux/kernel.h"
  5. /* Obviously procfs functions and macros */
  6. #include "linux/proc_fs.h"
  7. /* User Access (e.g. copy_to_user) */
  8. #include "linux/uaccess.h"
  9.  
  10. /* Names for our proc files */
  11. #define FIRST_PROC_FILE_NAME "ilovelinux"
  12. #define SECOND_PROC_FILE_NAME "kernelcodingisfun"
  13.  
  14. /*
  15.  * Enumerate our procfiles. We could have used literally everything that
  16.  * enables us to distinguish between the proc files.
  17.  */
  18. enum my_proc_files {
  19.   KERNEL_CODING_IS_FUN = 42,
  20.   I_LOVE_LINUX = 1337,
  21. };
  22.  
  23. /* Our proc file entries we are about to create */
  24. static struct proc_dir_entry *my_first_proc_file, *my_second_proc_file;
  25.  
  26. /* The read function called on read() syscall */
  27. static ssize_t my_proc_read(struct file *instance,
  28.                             char __user
  29.                             *user_buffer, size_t bytes_to_read,
  30.                             loff_t *offset)
  31. {
  32.   size_t to_copy, not_copied;
  33.   char buffer[30];
  34.   ulong identifier;
  35.  
  36.   /*
  37.    * Disallow seeking. We are far less than one page in size and this is just
  38.    * a simple example, but we do have an predictable data output, so it would
  39.    * be possible to allow seeking and therefore reading from a given offset.
  40.    */
  41.   if (*offset > 0)
  42.     return 0;
  43.  
  44.   /*
  45.    * Obtain the data associated with out PDE (proc_dir_entry) from a given
  46.    * struct file via its inode.
  47.    */
  48.   identifier = (ulong) PDE_DATA(file_inode(instance));
  49.   /* Now we can use it to make a simple and efficient distinction */
  50.   switch (identifier) {
  51.   case KERNEL_CODING_IS_FUN:
  52.     snprintf(buffer, sizeof(buffer), "Yes it is!\n");
  53.     break;
  54.  
  55.   case I_LOVE_LINUX:
  56.     snprintf(buffer, sizeof(buffer), "I do so too!\n");
  57.     break;
  58.  
  59.   default:
  60.     /*
  61.      * Well that would not be needed at all, but in case of you're not
  62.      * perfect and since this won't have a negative drawback on "good" runs,
  63.      * we should consider always adding a default branch since we did a
  64.      * cast and cannot rely on simply handling all values of our enum.
  65.      */
  66.     printk("proctest: this should never happen :c\n");
  67.     return -EFAULT;
  68.   }
  69.  
  70.   /*
  71.    * Generic part and thanks to a well defined kernel API pretty
  72.    * straightforward.
  73.    * It simply does a save copy of a null terminated string into the user
  74.    * buffer.
  75.    */
  76.   /* Do not exceed the users buffer size! */
  77.   to_copy = min(strlen(buffer) + 1, bytes_to_read);
  78.   /* The actual copy */
  79.   not_copied = copy_to_user(user_buffer, buffer, to_copy);
  80.   /*
  81.    * As usual to the read() syscall, return the bytes that were copied into
  82.    * the users buffer.
  83.    */
  84.   return *offset = to_copy - not_copied;
  85. }
  86.  
  87. static const struct file_operations proc_fops = {
  88.   .owner = THIS_MODULE,
  89.   .read  = my_proc_read, /* Bind the read function invoked on syscall */
  90. };
  91.  
  92. /* Module entry point */
  93. static int __init my_init(void)
  94. {
  95.   /* Create the proc file and... */
  96.   my_first_proc_file = proc_create_data(
  97.      /* ...give it a name */
  98.      FIRST_PROC_FILE_NAME,
  99.      /* ...access permissions (IRUGO == 0444 -> Read for User Group Other) */
  100.      S_IRUGO,
  101.      /* ...a root node (NULL means toplevel, so /proc) */
  102.      NULL,
  103.      /* ...bind the file operations (actually only read() is given) */
  104.      &proc_fops,
  105.      /*
  106.       * ...and associate some private data. As usual to private_data in the linux
  107.       * object model we may add here literally everything within the kernel
  108.       * address space. For our purpose it will do a simple enum/integer that we
  109.       * will use as an primitive identifier.
  110.       */
  111.      (void*)I_LOVE_LINUX);
  112.   if (!my_first_proc_file)
  113.     goto exit_error;
  114.  
  115.   /* Once again, another proc file */
  116.   my_second_proc_file = proc_create_data(SECOND_PROC_FILE_NAME,
  117.      S_IRUGO, NULL,
  118.      &proc_fops, (void*)KERNEL_CODING_IS_FUN);
  119.   if (!my_second_proc_file)
  120.     /* Never forget to cleanup on error */
  121.     goto cleanup_first;
  122.  
  123.   return 0;
  124.  
  125. cleanup_first:
  126.   remove_proc_entry(FIRST_PROC_FILE_NAME, NULL);
  127. exit_error:
  128.   return 1;
  129. }
  130.  
  131. /* Guess what. The modules exit */
  132. static void __exit my_exit(void)
  133. {
  134.   remove_proc_entry(SECOND_PROC_FILE_NAME, NULL);
  135.   remove_proc_entry(FIRST_PROC_FILE_NAME, NULL);
  136. }
  137.  
  138. module_init(my_init);
  139. module_exit(my_exit);
  140. MODULE_LICENSE("GPL");
  141. MODULE_AUTHOR("Sebastian Büttner <sebastian.buettner@iem.thm.de>")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement