diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/procfs1.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/procfs1.c new file mode 100644 index 00000000..92ad1801 --- /dev/null +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/procfs1.c @@ -0,0 +1,111 @@ +/* + * procfs1.c - create a "file" in /proc + * + */ + +#include /* Specifically, a module */ +#include /* We're doing kernel work */ +#include /* Necessary because we use the proc fs */ + +#define procfs_name "helloworld" + +/** + * This structure hold information about the /proc file + * + */ +struct proc_dir_entry *Our_Proc_File; + +/* Put data into the proc fs file. + * + * Arguments + * ========= + * 1. The buffer where the data is to be inserted, if + * you decide to use it. + * 2. A pointer to a pointer to characters. This is + * useful if you don't want to use the buffer + * allocated by the kernel. + * 3. The current position in the file + * 4. The size of the buffer in the first argument. + * 5. Write a "1" here to indicate EOF. + * 6. A pointer to data (useful in case one common + * read for multiple /proc/... entries) + * + * Usage and Return Value + * ====================== + * A return value of zero means you have no further + * information at this time (end of file). A negative + * return value is an error condition. + * + * For More Information + * ==================== + * The way I discovered what to do with this function + * wasn't by reading documentation, but by reading the + * code which used it. I just looked to see what uses + * the get_info field of proc_dir_entry struct (I used a + * combination of find and grep, if you're interested), + * and I saw that it is used in /fs/proc/array.c. + * + * If something is unknown about the kernel, this is + * usually the way to go. In Linux we have the great + * advantage of having the kernel source code for + * free - use it. + */ +int +procfile_read(char *buffer, + char **buffer_location, + off_t offset, int buffer_length, int *eof, void *data) +{ + int ret; + + printk(KERN_INFO "procfile_read (/proc/%s) called\n", procfs_name); + + /* + * We give all of our information in one go, so if the + * user asks us if we have more information the + * answer should always be no. + * + * This is important because the standard read + * function from the library would continue to issue + * the read system call until the kernel replies + * that it has no more information, or until its + * buffer is filled. + */ + if (offset > 0) { + /* we have finished to read, return 0 */ + ret = 0; + } else { + /* fill the buffer, return the buffer size */ + ret = sprintf(buffer, "HelloWorld!\n"); + } + + return ret; +} + +int init_module() +{ + Our_Proc_File = create_proc_entry(procfs_name, 0644, NULL); + + if (Our_Proc_File == NULL) { + remove_proc_entry(procfs_name, &proc_root); + printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", + procfs_name); + return -ENOMEM; + } + + Our_Proc_File->read_proc = procfile_read; + Our_Proc_File->owner = THIS_MODULE; + Our_Proc_File->mode = S_IFREG | S_IRUGO; + Our_Proc_File->uid = 0; + Our_Proc_File->gid = 0; + Our_Proc_File->size = 37; + + printk(KERN_INFO "/proc/%s created\n", procfs_name); + return 0; /* everything is ok */ +} + +void cleanup_module() +{ + remove_proc_entry(procfs_name, &proc_root); + printk(KERN_INFO "/proc/%s removed\n", procfs_name); +} diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/procfs2.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/procfs2.c new file mode 100644 index 00000000..d13a123c --- /dev/null +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/procfs2.c @@ -0,0 +1,114 @@ +/** + * procfs2.c - create a "file" in /proc + * + */ + +#include /* Specifically, a module */ +#include /* We're doing kernel work */ +#include /* Necessary because we use the proc fs */ +#include /* for copy_from_user */ + +#define PROCFS_MAX_SIZE 1024 +#define PROCFS_NAME "buffer1k" + +/** + * This structure hold information about the /proc file + * + */ +static struct proc_dir_entry *Our_Proc_File; + +/** + * The buffer used to store character for this module + * + */ +static char procfs_buffer[PROCFS_MAX_SIZE]; + +/** + * The size of the buffer + * + */ +static unsigned long procfs_buffer_size = 0; + +/** + * This function is called then the /proc file is read + * + */ +int +procfile_read(char *buffer, + char **buffer_location, + off_t offset, int buffer_length, int *eof, void *data) +{ + int ret; + + printk(KERN_INFO "procfile_read (/proc/%s) called\n", PROCFS_NAME); + + if (offset > 0) { + /* we have finished to read, return 0 */ + ret = 0; + } else { + /* fill the buffer, return the buffer size */ + memcpy(buffer, procfs_buffer, procfs_buffer_size); + ret = procfs_buffer_size; + } + + return ret; +} + +/** + * This function is called with the /proc file is written + * + */ +int procfile_write(struct file *file, const char *buffer, unsigned long count, + void *data) +{ + /* get buffer size */ + procfs_buffer_size = count; + if (procfs_buffer_size > PROCFS_MAX_SIZE ) { + procfs_buffer_size = PROCFS_MAX_SIZE; + } + + /* write data to the buffer */ + if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) ) { + return -EFAULT; + } + + return procfs_buffer_size; +} + +/** + *This function is called when the module is loaded + * + */ +int init_module() +{ + /* create the /proc file */ + Our_Proc_File = create_proc_entry(PROCFS_NAME, 0644, NULL); + + if (Our_Proc_File == NULL) { + remove_proc_entry(PROCFS_NAME, &proc_root); + printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", + PROCFS_NAME); + return -ENOMEM; + } + + Our_Proc_File->read_proc = procfile_read; + Our_Proc_File->write_proc = procfile_write; + Our_Proc_File->owner = THIS_MODULE; + Our_Proc_File->mode = S_IFREG | S_IRUGO; + Our_Proc_File->uid = 0; + Our_Proc_File->gid = 0; + Our_Proc_File->size = 37; + + printk(KERN_INFO "/proc/%s created\n", PROCFS_NAME); + return 0; /* everything is ok */ +} + +/** + *This function is called when the module is unloaded + * + */ +void cleanup_module() +{ + remove_proc_entry(PROCFS_NAME, &proc_root); + printk(KERN_INFO "/proc/%s removed\n", PROCFS_NAME); +} diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/procfs3.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/procfs3.c new file mode 100644 index 00000000..b406f8ef --- /dev/null +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/procfs3.c @@ -0,0 +1,197 @@ +/* + * procfs3.c - create a "file" in /proc, use the file_operation way + * to manage the file. + */ + +#include /* We're doing kernel work */ +#include /* Specifically, a module */ +#include /* Necessary because we use proc fs */ +#include /* for copy_*_user */ + +#define PROC_ENTRY_FILENAME "buffer2k" +#define PROCFS_MAX_SIZE 2048 + +/** + * The buffer (2k) for this module + * + */ +static char procfs_buffer[PROCFS_MAX_SIZE]; + +/** + * The size of the data hold in the buffer + * + */ +static unsigned long procfs_buffer_size = 0; + +/** + * The structure keeping information about the /proc file + * + */ +static struct proc_dir_entry *Our_Proc_File; + +/** + * This funtion is called when the /proc file is read + * + */ +static ssize_t procfs_read(struct file *filp, /* see include/linux/fs.h */ + char *buffer, /* buffer to fill with data */ + size_t length, /* length of the buffer */ + loff_t * offset) +{ + static int finished = 0; + + /* + * We return 0 to indicate end of file, that we have + * no more information. Otherwise, processes will + * continue to read from us in an endless loop. + */ + if ( finished ) { + printk(KERN_INFO "procfs_read: END\n"); + finished = 0; + return 0; + } + + finished = 1; + + /* + * We use put_to_user to copy the string from the kernel's + * memory segment to the memory segment of the process + * that called us. get_from_user, BTW, is + * used for the reverse. + */ + if ( copy_to_user(buffer, procfs_buffer, procfs_buffer_size) ) { + return -EFAULT; + } + + printk(KERN_INFO "procfs_read: read %lu bytes\n", procfs_buffer_size); + + return procfs_buffer_size; /* Return the number of bytes "read" */ +} + +/* + * This function is called when /proc is written + */ +static ssize_t +procfs_write(struct file *file, const char *buffer, size_t len, loff_t * off) +{ + if ( len > PROCFS_MAX_SIZE ) { + procfs_buffer_size = PROCFS_MAX_SIZE; + } + else { + procfs_buffer_size = len; + } + + if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) ) { + return -EFAULT; + } + + printk(KERN_INFO "procfs_write: write %lu bytes\n", procfs_buffer_size); + + return procfs_buffer_size; +} + +/* + * This function decides whether to allow an operation + * (return zero) or not allow it (return a non-zero + * which indicates why it is not allowed). + * + * The operation can be one of the following values: + * 0 - Execute (run the "file" - meaningless in our case) + * 2 - Write (input to the kernel module) + * 4 - Read (output from the kernel module) + * + * This is the real function that checks file + * permissions. The permissions returned by ls -l are + * for referece only, and can be overridden here. + */ + +static int module_permission(struct inode *inode, int op, struct nameidata *foo) +{ + /* + * We allow everybody to read from our module, but + * only root (uid 0) may write to it + */ + if (op == 4 || (op == 2 && current->euid == 0)) + return 0; + + /* + * If it's anything else, access is denied + */ + return -EACCES; +} + +/* + * The file is opened - we don't really care about + * that, but it does mean we need to increment the + * module's reference count. + */ +int procfs_open(struct inode *inode, struct file *file) +{ + try_module_get(THIS_MODULE); + return 0; +} + +/* + * The file is closed - again, interesting only because + * of the reference count. + */ +int procfs_close(struct inode *inode, struct file *file) +{ + module_put(THIS_MODULE); + return 0; /* success */ +} + +static struct file_operations File_Ops_4_Our_Proc_File = { + .read = procfs_read, + .write = procfs_write, + .open = procfs_open, + .release = procfs_close, +}; + +/* + * Inode operations for our proc file. We need it so + * we'll have some place to specify the file operations + * structure we want to use, and the function we use for + * permissions. It's also possible to specify functions + * to be called for anything else which could be done to + * an inode (although we don't bother, we just put + * NULL). + */ + +static struct inode_operations Inode_Ops_4_Our_Proc_File = { + .permission = module_permission, /* check for permissions */ +}; + +/* + * Module initialization and cleanup + */ +int init_module() +{ + /* create the /proc file */ + Our_Proc_File = create_proc_entry(PROC_ENTRY_FILENAME, 0644, NULL); + + /* check if the /proc file was created successfuly */ + if (Our_Proc_File == NULL){ + printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", + PROC_ENTRY_FILENAME); + return -ENOMEM; + } + + Our_Proc_File->owner = THIS_MODULE; + Our_Proc_File->proc_iops = &Inode_Ops_4_Our_Proc_File; + Our_Proc_File->proc_fops = &File_Ops_4_Our_Proc_File; + Our_Proc_File->mode = S_IFREG | S_IRUGO | S_IWUSR; + Our_Proc_File->uid = 0; + Our_Proc_File->gid = 0; + Our_Proc_File->size = 80; + + printk(KERN_INFO "/proc/%s created\n", PROC_ENTRY_FILENAME); + + return 0; /* success */ +} + +void cleanup_module() +{ + remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root); + printk(KERN_INFO "/proc/%s removed\n", PROC_ENTRY_FILENAME); +} diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/09-BlockingProcesses/cat_noblock.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/09-BlockingProcesses/cat_noblock.c new file mode 100644 index 00000000..80dd3d7b --- /dev/null +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/09-BlockingProcesses/cat_noblock.c @@ -0,0 +1,68 @@ +/* cat_noblock.c - open a file and display its contents, but exit rather than + * wait for input */ + + +/* Copyright (C) 1998 by Ori Pomerantz */ + + + +#include /* standard I/O */ +#include /* for open */ +#include /* for read */ +#include /* for exit */ +#include /* for errno */ + +#define MAX_BYTES 1024*4 + + +main(int argc, char *argv[]) +{ + int fd; /* The file descriptor for the file to read */ + size_t bytes; /* The number of bytes read */ + char buffer[MAX_BYTES]; /* The buffer for the bytes */ + + + /* Usage */ + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + puts("Reads the content of a file, but doesn't wait for input"); + exit(-1); + } + + /* Open the file for reading in non blocking mode */ + fd = open(argv[1], O_RDONLY | O_NONBLOCK); + + /* If open failed */ + if (fd == -1) { + if (errno = EAGAIN) + puts("Open would block"); + else + puts("Open failed"); + exit(-1); + } + + /* Read the file and output its contents */ + do { + int i; + + /* Read characters from the file */ + bytes = read(fd, buffer, MAX_BYTES); + + /* If there's an error, report it and die */ + if (bytes == -1) { + if (errno = EAGAIN) + puts("Normally I'd block, but you told me not to"); + else + puts("Another read error"); + exit(-1); + } + + /* Print the characters */ + if (bytes > 0) { + for(i=0; i 0); +}