1 /* procobjecttree.c
2 *
3 * Copyright (C) 2010 - 2013 UNISYS CORPORATION
4 * All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14 * NON INFRINGEMENT. See the GNU General Public License for more
15 * details.
16 */
17
18 #include "procobjecttree.h"
19
20 #define MYDRVNAME "procobjecttree"
21
22
23
24 /** This is context info that we stash in each /proc file entry, which we
25 * need in order to call the callback function that supplies the /proc read
26 * info for that file.
27 */
28 typedef struct {
29 void (*show_property)(struct seq_file *, void *, int);
30 MYPROCOBJECT *procObject;
31 int propertyIndex;
32
33 } PROCDIRENTRYCONTEXT;
34
35 /** This describes the attributes of a tree rooted at
36 * <procDirRoot>/<name[0]>/<name[1]>/...
37 * Properties for each object of this type will be located under
38 * <procDirRoot>/<name[0]>/<name[1]>/.../<objectName>/<propertyName>.
39 */
40 struct MYPROCTYPE_Tag {
41 const char **name; /**< node names for this type, ending with NULL */
42 int nNames; /**< num of node names in <name> */
43
44 /** root dir for this type tree in /proc */
45 struct proc_dir_entry *procDirRoot;
46
47 struct proc_dir_entry **procDirs; /**< for each node in <name> */
48
49 /** bottom dir where objects will be rooted; i.e., this is
50 * <procDirRoot>/<name[0]>/<name[1]>/.../, which is the same as the
51 * last entry in the <procDirs> array. */
52 struct proc_dir_entry *procDir;
53
54 /** name for each property that objects of this type can have */
55 const char **propertyNames;
56
57 int nProperties; /**< num of names in <propertyNames> */
58
59 /** Call this, passing MYPROCOBJECT.context and the property index
60 * whenever someone reads the proc entry */
61 void (*show_property)(struct seq_file *, void *, int);
62 };
63
64
65
66 struct MYPROCOBJECT_Tag {
67 MYPROCTYPE *type;
68
69 /** This is the name of the dir node in /proc under which the
70 * properties of this object will appear as files. */
71 char *name;
72
73 int namesize; /**< number of bytes allocated for name */
74 void *context; /**< passed to MYPROCTYPE.show_property */
75
76 /** <type.procDirRoot>/<type.name[0]>/<type.name[1]>/.../<name> */
77 struct proc_dir_entry *procDir;
78
79 /** a proc dir entry for each of the properties of the object;
80 * properties are identified in MYPROCTYPE.propertyNames, so each of
81 * the <procDirProperties> describes a single file like
82 * <type.procDirRoot>/<type.name[0]>/<type.name[1]>/...
83 * /<name>/<propertyName>
84 */
85 struct proc_dir_entry **procDirProperties;
86
87 /** this is a holding area for the context information that is needed
88 * to run the /proc callback function */
89 PROCDIRENTRYCONTEXT *procDirPropertyContexts;
90 };
91
92
93
94 static struct proc_dir_entry *
createProcDir(const char * name,struct proc_dir_entry * parent)95 createProcDir(const char *name, struct proc_dir_entry *parent)
96 {
97 struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent);
98
99 if (p == NULL)
100 ERRDRV("failed to create /proc directory %s", name);
101 return p;
102 }
103
104 static struct proc_dir_entry *
createProcFile(const char * name,struct proc_dir_entry * parent,const struct file_operations * fops,void * data)105 createProcFile(const char *name, struct proc_dir_entry *parent,
106 const struct file_operations *fops, void *data)
107 {
108 struct proc_dir_entry *p = proc_create_data(name, 0, parent,
109 fops, data);
110 if (p == NULL)
111 ERRDRV("failed to create /proc file %s", name);
112 return p;
113 }
114
115 static int seq_show(struct seq_file *seq, void *offset);
proc_open(struct inode * inode,struct file * file)116 static int proc_open(struct inode *inode, struct file *file)
117 {
118 return single_open(file, seq_show, PDE_DATA(inode));
119 }
120
121 static const struct file_operations proc_fops = {
122 .open = proc_open,
123 .read = seq_read,
124 .llseek = seq_lseek,
125 .release = single_release,
126 };
127
128
129
visor_proc_CreateType(struct proc_dir_entry * procDirRoot,const char ** name,const char ** propertyNames,void (* show_property)(struct seq_file *,void *,int))130 MYPROCTYPE *visor_proc_CreateType(struct proc_dir_entry *procDirRoot,
131 const char **name,
132 const char **propertyNames,
133 void (*show_property)(struct seq_file *,
134 void *, int))
135 {
136 int i = 0;
137 MYPROCTYPE *rc = NULL, *type = NULL;
138 struct proc_dir_entry *parent = NULL;
139
140 if (procDirRoot == NULL) {
141 ERRDRV("procDirRoot cannot be NULL!\n");
142 goto Away;
143 }
144 if (name == NULL || name[0] == NULL) {
145 ERRDRV("name must contain at least 1 node name!\n");
146 goto Away;
147 }
148 type = kzalloc(sizeof(MYPROCTYPE), GFP_KERNEL | __GFP_NORETRY);
149 if (type == NULL) {
150 ERRDRV("out of memory\n");
151 goto Away;
152 }
153 type->name = name;
154 type->propertyNames = propertyNames;
155 type->nProperties = 0;
156 type->nNames = 0;
157 type->show_property = show_property;
158 type->procDirRoot = procDirRoot;
159 if (type->propertyNames != NULL)
160 while (type->propertyNames[type->nProperties] != NULL)
161 type->nProperties++;
162 while (type->name[type->nNames] != NULL)
163 type->nNames++;
164 type->procDirs = kzalloc((type->nNames + 1) *
165 sizeof(struct proc_dir_entry *),
166 GFP_KERNEL | __GFP_NORETRY);
167 if (type->procDirs == NULL) {
168 ERRDRV("out of memory\n");
169 goto Away;
170 }
171 parent = procDirRoot;
172 for (i = 0; i < type->nNames; i++) {
173 type->procDirs[i] = createProcDir(type->name[i], parent);
174 if (type->procDirs[i] == NULL) {
175 rc = NULL;
176 goto Away;
177 }
178 parent = type->procDirs[i];
179 }
180 type->procDir = type->procDirs[type->nNames-1];
181 rc = type;
182 Away:
183 if (rc == NULL) {
184 if (type != NULL) {
185 visor_proc_DestroyType(type);
186 type = NULL;
187 }
188 }
189 return rc;
190 }
191 EXPORT_SYMBOL_GPL(visor_proc_CreateType);
192
193
194
visor_proc_DestroyType(MYPROCTYPE * type)195 void visor_proc_DestroyType(MYPROCTYPE *type)
196 {
197 if (type == NULL)
198 return;
199 if (type->procDirs != NULL) {
200 int i = type->nNames-1;
201
202 while (i >= 0) {
203 if (type->procDirs[i] != NULL) {
204 struct proc_dir_entry *parent = NULL;
205
206 if (i == 0)
207 parent = type->procDirRoot;
208 else
209 parent = type->procDirs[i-1];
210 remove_proc_entry(type->name[i], parent);
211 }
212 i--;
213 }
214 kfree(type->procDirs);
215 type->procDirs = NULL;
216 }
217 kfree(type);
218 }
219 EXPORT_SYMBOL_GPL(visor_proc_DestroyType);
220
221
222
visor_proc_CreateObject(MYPROCTYPE * type,const char * name,void * context)223 MYPROCOBJECT *visor_proc_CreateObject(MYPROCTYPE *type,
224 const char *name, void *context)
225 {
226 MYPROCOBJECT *obj = NULL, *rc = NULL;
227 int i = 0;
228
229 if (type == NULL) {
230 ERRDRV("type cannot be NULL\n");
231 goto Away;
232 }
233 obj = kzalloc(sizeof(MYPROCOBJECT), GFP_KERNEL | __GFP_NORETRY);
234 if (obj == NULL) {
235 ERRDRV("out of memory\n");
236 goto Away;
237 }
238 obj->type = type;
239 obj->context = context;
240 if (name == NULL) {
241 obj->name = NULL;
242 obj->procDir = type->procDir;
243 } else {
244 obj->namesize = strlen(name)+1;
245 obj->name = kmalloc(obj->namesize, GFP_KERNEL | __GFP_NORETRY);
246 if (obj->name == NULL) {
247 obj->namesize = 0;
248 ERRDRV("out of memory\n");
249 goto Away;
250 }
251 strcpy(obj->name, name);
252 obj->procDir = createProcDir(obj->name, type->procDir);
253 if (obj->procDir == NULL)
254 goto Away;
255 }
256 obj->procDirPropertyContexts =
257 kzalloc((type->nProperties + 1) * sizeof(PROCDIRENTRYCONTEXT),
258 GFP_KERNEL | __GFP_NORETRY);
259 if (obj->procDirPropertyContexts == NULL) {
260 ERRDRV("out of memory\n");
261 goto Away;
262 }
263 obj->procDirProperties =
264 kzalloc((type->nProperties + 1) * sizeof(struct proc_dir_entry *),
265 GFP_KERNEL | __GFP_NORETRY);
266 if (obj->procDirProperties == NULL) {
267 ERRDRV("out of memory\n");
268 goto Away;
269 }
270 for (i = 0; i < type->nProperties; i++) {
271 obj->procDirPropertyContexts[i].procObject = obj;
272 obj->procDirPropertyContexts[i].propertyIndex = i;
273 obj->procDirPropertyContexts[i].show_property =
274 type->show_property;
275 if (type->propertyNames[i][0] != '\0') {
276 /* only create properties that have names */
277 obj->procDirProperties[i] =
278 createProcFile(type->propertyNames[i],
279 obj->procDir, &proc_fops,
280 &obj->procDirPropertyContexts[i]);
281 if (obj->procDirProperties[i] == NULL) {
282 rc = NULL;
283 goto Away;
284 }
285 }
286 }
287 rc = obj;
288 Away:
289 if (rc == NULL) {
290 if (obj != NULL) {
291 visor_proc_DestroyObject(obj);
292 obj = NULL;
293 }
294 }
295 return rc;
296 }
297 EXPORT_SYMBOL_GPL(visor_proc_CreateObject);
298
299
300
visor_proc_DestroyObject(MYPROCOBJECT * obj)301 void visor_proc_DestroyObject(MYPROCOBJECT *obj)
302 {
303 MYPROCTYPE *type = NULL;
304
305 if (obj == NULL)
306 return;
307 type = obj->type;
308 if (type == NULL)
309 return;
310 if (obj->procDirProperties != NULL) {
311 int i = 0;
312
313 for (i = 0; i < type->nProperties; i++) {
314 if (obj->procDirProperties[i] != NULL) {
315 remove_proc_entry(type->propertyNames[i],
316 obj->procDir);
317 obj->procDirProperties[i] = NULL;
318 }
319 }
320 kfree(obj->procDirProperties);
321 obj->procDirProperties = NULL;
322 }
323 if (obj->procDirPropertyContexts != NULL) {
324 kfree(obj->procDirPropertyContexts);
325 obj->procDirPropertyContexts = NULL;
326 }
327 if (obj->procDir != NULL) {
328 if (obj->name != NULL)
329 remove_proc_entry(obj->name, type->procDir);
330 obj->procDir = NULL;
331 }
332 if (obj->name != NULL) {
333 kfree(obj->name);
334 obj->name = NULL;
335 }
336 kfree(obj);
337 }
338 EXPORT_SYMBOL_GPL(visor_proc_DestroyObject);
339
340
341
seq_show(struct seq_file * seq,void * offset)342 static int seq_show(struct seq_file *seq, void *offset)
343 {
344 PROCDIRENTRYCONTEXT *ctx = (PROCDIRENTRYCONTEXT *)(seq->private);
345
346 if (ctx == NULL) {
347 ERRDRV("I don't have a freakin' clue...");
348 return 0;
349 }
350 (*ctx->show_property)(seq, ctx->procObject->context,
351 ctx->propertyIndex);
352 return 0;
353 }
354