mirror of https://github.com/tLDP/LDP
new
This commit is contained in:
parent
77ba6298b3
commit
47c55a069e
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* procfs1.c - create a "file" in /proc
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h> /* Specifically, a module */
|
||||
#include <linux/kernel.h> /* We're doing kernel work */
|
||||
#include <linux/proc_fs.h> /* 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 <kernel source
|
||||
* directory>/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);
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/**
|
||||
* procfs2.c - create a "file" in /proc
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h> /* Specifically, a module */
|
||||
#include <linux/kernel.h> /* We're doing kernel work */
|
||||
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
|
||||
#include <asm/uaccess.h> /* 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);
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* procfs3.c - create a "file" in /proc, use the file_operation way
|
||||
* to manage the file.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h> /* We're doing kernel work */
|
||||
#include <linux/module.h> /* Specifically, a module */
|
||||
#include <linux/proc_fs.h> /* Necessary because we use proc fs */
|
||||
#include <asm/uaccess.h> /* 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);
|
||||
}
|
|
@ -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 <stdio.h> /* standard I/O */
|
||||
#include <fcntl.h> /* for open */
|
||||
#include <unistd.h> /* for read */
|
||||
#include <stdlib.h> /* for exit */
|
||||
#include <errno.h> /* 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 <filename>\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<bytes; i++)
|
||||
putchar(buffer[i]);
|
||||
}
|
||||
|
||||
/* While there are no errors and the file isn't over */
|
||||
} while (bytes > 0);
|
||||
}
|
Loading…
Reference in New Issue