mirror of
https://github.com/sysprog21/lkmpg.git
synced 2024-11-29 12:16:41 +08:00
8f32341bee
In rendered HTML, the line number should be right aligned, and code should be left aligned accordingly. In addition, this patch added the basic build instructions, so that someone can generated the PDF and HTML files. Close #44
117 lines
2.9 KiB
C
117 lines
2.9 KiB
C
/*
|
|
* procfs4.c - create a "file" in /proc
|
|
* This program uses the seq_file library to manage the /proc file.
|
|
*/
|
|
|
|
#include <linux/kernel.h> /* We are doing kernel work */
|
|
#include <linux/module.h> /* Specifically, a module */
|
|
#include <linux/proc_fs.h> /* Necessary because we use proc fs */
|
|
#include <linux/seq_file.h> /* for seq_file */
|
|
#include <linux/version.h>
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
|
#define HAVE_PROC_OPS
|
|
#endif
|
|
|
|
#define PROC_NAME "iter"
|
|
|
|
/* This function is called at the beginning of a sequence.
|
|
* ie, when:
|
|
* - the /proc file is read (first time)
|
|
* - after the function stop (end of sequence)
|
|
*/
|
|
static void *my_seq_start(struct seq_file *s, loff_t *pos)
|
|
{
|
|
static unsigned long counter = 0;
|
|
|
|
/* beginning a new sequence? */
|
|
if (*pos == 0) {
|
|
/* yes => return a non null value to begin the sequence */
|
|
return &counter;
|
|
}
|
|
/* no => it is the end of the sequence, return end to stop reading */
|
|
*pos = 0;
|
|
return NULL;
|
|
}
|
|
|
|
/* This function is called after the beginning of a sequence.
|
|
* It is called untill the return is NULL (this ends the sequence).
|
|
*/
|
|
static void *my_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
|
{
|
|
unsigned long *tmp_v = (unsigned long *) v;
|
|
(*tmp_v)++;
|
|
(*pos)++;
|
|
return NULL;
|
|
}
|
|
|
|
/* This function is called at the end of a sequence. */
|
|
static void my_seq_stop(struct seq_file *s, void *v)
|
|
{
|
|
/* nothing to do, we use a static value in start() */
|
|
}
|
|
|
|
/* This function is called for each "step" of a sequence. */
|
|
static int my_seq_show(struct seq_file *s, void *v)
|
|
{
|
|
loff_t *spos = (loff_t *) v;
|
|
|
|
seq_printf(s, "%Ld\n", *spos);
|
|
return 0;
|
|
}
|
|
|
|
/* This structure gather "function" to manage the sequence */
|
|
static struct seq_operations my_seq_ops = {
|
|
.start = my_seq_start,
|
|
.next = my_seq_next,
|
|
.stop = my_seq_stop,
|
|
.show = my_seq_show,
|
|
};
|
|
|
|
/* This function is called when the /proc file is open. */
|
|
static int my_open(struct inode *inode, struct file *file)
|
|
{
|
|
return seq_open(file, &my_seq_ops);
|
|
};
|
|
|
|
/* This structure gather "function" that manage the /proc file */
|
|
#ifdef HAVE_PROC_OPS
|
|
static const struct proc_ops my_file_ops = {
|
|
.proc_open = my_open,
|
|
.proc_read = seq_read,
|
|
.proc_lseek = seq_lseek,
|
|
.proc_release = seq_release,
|
|
};
|
|
#else
|
|
static const struct file_operations my_file_ops = {
|
|
.open = my_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = seq_release,
|
|
};
|
|
#endif
|
|
|
|
static int __init procfs4_init(void)
|
|
{
|
|
struct proc_dir_entry *entry;
|
|
|
|
entry = proc_create(PROC_NAME, 0, NULL, &my_file_ops);
|
|
if (entry == NULL) {
|
|
remove_proc_entry(PROC_NAME, NULL);
|
|
pr_debug("Error: Could not initialize /proc/%s\n", PROC_NAME);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __exit procfs4_exit(void)
|
|
{
|
|
remove_proc_entry(PROC_NAME, NULL);
|
|
pr_debug("/proc/%s removed\n", PROC_NAME);
|
|
}
|
|
|
|
module_init(procfs4_init);
|
|
module_exit(procfs4_exit);
|
|
|
|
MODULE_LICENSE("GPL"); |