blob: 8c6396e4bf311901a19fd717500c422eeba4869a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * procfs_example.c: an example proc interface
3 *
Randy Dunlap758222f2008-10-15 22:04:14 -07004 * Copyright (C) 2001, Erik Mouw (mouw@nl.linux.org)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
6 * This file accompanies the procfs-guide in the Linux kernel
7 * source. Its main use is to demonstrate the concepts and
8 * functions described in the guide.
9 *
10 * This software has been developed while working on the LART
Randy Dunlap758222f2008-10-15 22:04:14 -070011 * computing board (http://www.lartmaker.nl), which was sponsored
12 * by the Delt University of Technology projects Mobile Multi-media
13 * Communications and Ubiquitous Communications.
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 *
15 * This program is free software; you can redistribute
16 * it and/or modify it under the terms of the GNU General
17 * Public License as published by the Free Software
18 * Foundation; either version 2 of the License, or (at your
19 * option) any later version.
20 *
21 * This program is distributed in the hope that it will be
22 * useful, but WITHOUT ANY WARRANTY; without even the implied
23 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
24 * PURPOSE. See the GNU General Public License for more
25 * details.
26 *
27 * You should have received a copy of the GNU General Public
28 * License along with this program; if not, write to the
29 * Free Software Foundation, Inc., 59 Temple Place,
30 * Suite 330, Boston, MA 02111-1307 USA
31 *
32 */
33
34#include <linux/module.h>
35#include <linux/kernel.h>
36#include <linux/init.h>
37#include <linux/proc_fs.h>
38#include <linux/jiffies.h>
39#include <asm/uaccess.h>
40
41
42#define MODULE_VERS "1.0"
43#define MODULE_NAME "procfs_example"
44
45#define FOOBAR_LEN 8
46
47struct fb_data_t {
48 char name[FOOBAR_LEN + 1];
49 char value[FOOBAR_LEN + 1];
50};
51
52
53static struct proc_dir_entry *example_dir, *foo_file,
54 *bar_file, *jiffies_file, *symlink;
55
56
57struct fb_data_t foo_data, bar_data;
58
59
60static int proc_read_jiffies(char *page, char **start,
61 off_t off, int count,
62 int *eof, void *data)
63{
64 int len;
65
66 len = sprintf(page, "jiffies = %ld\n",
67 jiffies);
68
69 return len;
70}
71
72
73static int proc_read_foobar(char *page, char **start,
74 off_t off, int count,
75 int *eof, void *data)
76{
77 int len;
78 struct fb_data_t *fb_data = (struct fb_data_t *)data;
79
80 /* DON'T DO THAT - buffer overruns are bad */
81 len = sprintf(page, "%s = '%s'\n",
82 fb_data->name, fb_data->value);
83
84 return len;
85}
86
87
88static int proc_write_foobar(struct file *file,
89 const char *buffer,
90 unsigned long count,
91 void *data)
92{
93 int len;
94 struct fb_data_t *fb_data = (struct fb_data_t *)data;
95
96 if(count > FOOBAR_LEN)
97 len = FOOBAR_LEN;
98 else
99 len = count;
100
101 if(copy_from_user(fb_data->value, buffer, len))
102 return -EFAULT;
103
104 fb_data->value[len] = '\0';
105
106 return len;
107}
108
109
110static int __init init_procfs_example(void)
111{
112 int rv = 0;
113
114 /* create directory */
115 example_dir = proc_mkdir(MODULE_NAME, NULL);
116 if(example_dir == NULL) {
117 rv = -ENOMEM;
118 goto out;
119 }
120
121 example_dir->owner = THIS_MODULE;
122
123 /* create jiffies using convenience function */
124 jiffies_file = create_proc_read_entry("jiffies",
125 0444, example_dir,
126 proc_read_jiffies,
127 NULL);
128 if(jiffies_file == NULL) {
129 rv = -ENOMEM;
130 goto no_jiffies;
131 }
132
133 jiffies_file->owner = THIS_MODULE;
134
135 /* create foo and bar files using same callback
136 * functions
137 */
138 foo_file = create_proc_entry("foo", 0644, example_dir);
139 if(foo_file == NULL) {
140 rv = -ENOMEM;
141 goto no_foo;
142 }
143
144 strcpy(foo_data.name, "foo");
145 strcpy(foo_data.value, "foo");
146 foo_file->data = &foo_data;
147 foo_file->read_proc = proc_read_foobar;
148 foo_file->write_proc = proc_write_foobar;
149 foo_file->owner = THIS_MODULE;
150
151 bar_file = create_proc_entry("bar", 0644, example_dir);
152 if(bar_file == NULL) {
153 rv = -ENOMEM;
154 goto no_bar;
155 }
156
157 strcpy(bar_data.name, "bar");
158 strcpy(bar_data.value, "bar");
159 bar_file->data = &bar_data;
160 bar_file->read_proc = proc_read_foobar;
161 bar_file->write_proc = proc_write_foobar;
162 bar_file->owner = THIS_MODULE;
163
164 /* create symlink */
165 symlink = proc_symlink("jiffies_too", example_dir,
166 "jiffies");
167 if(symlink == NULL) {
168 rv = -ENOMEM;
169 goto no_symlink;
170 }
171
172 symlink->owner = THIS_MODULE;
173
174 /* everything OK */
175 printk(KERN_INFO "%s %s initialised\n",
176 MODULE_NAME, MODULE_VERS);
177 return 0;
178
179no_symlink:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 remove_proc_entry("bar", example_dir);
181no_bar:
182 remove_proc_entry("foo", example_dir);
183no_foo:
184 remove_proc_entry("jiffies", example_dir);
185no_jiffies:
186 remove_proc_entry(MODULE_NAME, NULL);
187out:
188 return rv;
189}
190
191
192static void __exit cleanup_procfs_example(void)
193{
194 remove_proc_entry("jiffies_too", example_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 remove_proc_entry("bar", example_dir);
196 remove_proc_entry("foo", example_dir);
197 remove_proc_entry("jiffies", example_dir);
198 remove_proc_entry(MODULE_NAME, NULL);
199
200 printk(KERN_INFO "%s %s removed\n",
201 MODULE_NAME, MODULE_VERS);
202}
203
204
205module_init(init_procfs_example);
206module_exit(cleanup_procfs_example);
207
208MODULE_AUTHOR("Erik Mouw");
209MODULE_DESCRIPTION("procfs examples");
Randy Dunlap5d39d942008-08-12 15:09:06 -0700210MODULE_LICENSE("GPL");