Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Required for all modules */
- #include "linux/init.h"
- #include "linux/module.h"
- #include "linux/kernel.h"
- /* Obviously procfs functions and macros */
- #include "linux/proc_fs.h"
- /* User Access (e.g. copy_to_user) */
- #include "linux/uaccess.h"
- /* Names for our proc files */
- #define FIRST_PROC_FILE_NAME "ilovelinux"
- #define SECOND_PROC_FILE_NAME "kernelcodingisfun"
- /*
- * Enumerate our procfiles. We could have used literally everything that
- * enables us to distinguish between the proc files.
- */
- enum my_proc_files {
- KERNEL_CODING_IS_FUN = 42,
- I_LOVE_LINUX = 1337,
- };
- /* Our proc file entries we are about to create */
- static struct proc_dir_entry *my_first_proc_file, *my_second_proc_file;
- /* The read function called on read() syscall */
- static ssize_t my_proc_read(struct file *instance,
- char __user
- *user_buffer, size_t bytes_to_read,
- loff_t *offset)
- {
- size_t to_copy, not_copied;
- char buffer[30];
- ulong identifier;
- /*
- * Disallow seeking. We are far less than one page in size and this is just
- * a simple example, but we do have an predictable data output, so it would
- * be possible to allow seeking and therefore reading from a given offset.
- */
- if (*offset > 0)
- return 0;
- /*
- * Obtain the data associated with out PDE (proc_dir_entry) from a given
- * struct file via its inode.
- */
- identifier = (ulong) PDE_DATA(file_inode(instance));
- /* Now we can use it to make a simple and efficient distinction */
- switch (identifier) {
- case KERNEL_CODING_IS_FUN:
- snprintf(buffer, sizeof(buffer), "Yes it is!\n");
- break;
- case I_LOVE_LINUX:
- snprintf(buffer, sizeof(buffer), "I do so too!\n");
- break;
- default:
- /*
- * Well that would not be needed at all, but in case of you're not
- * perfect and since this won't have a negative drawback on "good" runs,
- * we should consider always adding a default branch since we did a
- * cast and cannot rely on simply handling all values of our enum.
- */
- printk("proctest: this should never happen :c\n");
- return -EFAULT;
- }
- /*
- * Generic part and thanks to a well defined kernel API pretty
- * straightforward.
- * It simply does a save copy of a null terminated string into the user
- * buffer.
- */
- /* Do not exceed the users buffer size! */
- to_copy = min(strlen(buffer) + 1, bytes_to_read);
- /* The actual copy */
- not_copied = copy_to_user(user_buffer, buffer, to_copy);
- /*
- * As usual to the read() syscall, return the bytes that were copied into
- * the users buffer.
- */
- return *offset = to_copy - not_copied;
- }
- static const struct file_operations proc_fops = {
- .owner = THIS_MODULE,
- .read = my_proc_read, /* Bind the read function invoked on syscall */
- };
- /* Module entry point */
- static int __init my_init(void)
- {
- /* Create the proc file and... */
- my_first_proc_file = proc_create_data(
- /* ...give it a name */
- FIRST_PROC_FILE_NAME,
- /* ...access permissions (IRUGO == 0444 -> Read for User Group Other) */
- S_IRUGO,
- /* ...a root node (NULL means toplevel, so /proc) */
- NULL,
- /* ...bind the file operations (actually only read() is given) */
- &proc_fops,
- /*
- * ...and associate some private data. As usual to private_data in the linux
- * object model we may add here literally everything within the kernel
- * address space. For our purpose it will do a simple enum/integer that we
- * will use as an primitive identifier.
- */
- (void*)I_LOVE_LINUX);
- if (!my_first_proc_file)
- goto exit_error;
- /* Once again, another proc file */
- my_second_proc_file = proc_create_data(SECOND_PROC_FILE_NAME,
- S_IRUGO, NULL,
- &proc_fops, (void*)KERNEL_CODING_IS_FUN);
- if (!my_second_proc_file)
- /* Never forget to cleanup on error */
- goto cleanup_first;
- return 0;
- cleanup_first:
- remove_proc_entry(FIRST_PROC_FILE_NAME, NULL);
- exit_error:
- return 1;
- }
- /* Guess what. The modules exit */
- static void __exit my_exit(void)
- {
- remove_proc_entry(SECOND_PROC_FILE_NAME, NULL);
- remove_proc_entry(FIRST_PROC_FILE_NAME, NULL);
- }
- module_init(my_init);
- module_exit(my_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Sebastian Büttner <sebastian.buettner@iem.thm.de>")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement