procobjecttree.c revision 927c7927eee73e195afc5b76ffb91bd72e3cb03d
1/* procobjecttree.c
2 *
3 * Copyright � 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 */
28typedef 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 */
40struct 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
66struct 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
94static struct proc_dir_entry *
95createProcDir(const char *name, struct proc_dir_entry *parent)
96{
97	struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent);
98	if (p == NULL)
99		ERRDRV("failed to create /proc directory %s", name);
100	return p;
101}
102
103static struct proc_dir_entry *
104createProcFile(const char *name, struct proc_dir_entry *parent,
105	       const struct file_operations *fops, void *data)
106{
107	struct proc_dir_entry *p = proc_create_data(name, 0, parent,
108						    fops, data);
109	if (p == NULL)
110		ERRDRV("failed to create /proc file %s", name);
111	return p;
112}
113
114static int seq_show(struct seq_file *seq, void *offset);
115static int proc_open(struct inode *inode, struct file *file)
116{
117	return single_open(file, seq_show, PDE_DATA(inode));
118}
119
120static const struct file_operations proc_fops = {
121	.open = proc_open,
122	.read = seq_read,
123	.llseek = seq_lseek,
124	.release = single_release,
125};
126
127
128
129MYPROCTYPE *visor_proc_CreateType(struct proc_dir_entry *procDirRoot,
130				  const char **name,
131				  const char **propertyNames,
132				  void (*show_property)(struct seq_file *,
133							void *, int))
134{
135	int i = 0;
136	MYPROCTYPE *rc = NULL, *type = NULL;
137	struct proc_dir_entry *parent = NULL;
138
139	if (procDirRoot == NULL)
140		FAIL("procDirRoot cannot be NULL!", 0);
141	if (name == NULL || name[0] == NULL)
142		FAIL("name must contain at least 1 node name!", 0);
143	type = kmalloc(sizeof(MYPROCTYPE), GFP_KERNEL|__GFP_NORETRY);
144	if (type == NULL)
145		FAIL("out of memory", 0);
146	memset(type, 0, sizeof(MYPROCTYPE));
147	type->name = name;
148	type->propertyNames = propertyNames;
149	type->nProperties = 0;
150	type->nNames = 0;
151	type->show_property = show_property;
152	type->procDirRoot = procDirRoot;
153	if (type->propertyNames != 0)
154		while (type->propertyNames[type->nProperties] != NULL)
155			type->nProperties++;
156	while (type->name[type->nNames] != NULL)
157		type->nNames++;
158	type->procDirs = kmalloc((type->nNames+1)*
159				 sizeof(struct proc_dir_entry *),
160				 GFP_KERNEL|__GFP_NORETRY);
161	if (type->procDirs == NULL)
162		FAIL("out of memory", 0);
163	memset(type->procDirs, 0, (type->nNames + 1) *
164	       sizeof(struct proc_dir_entry *));
165	parent = procDirRoot;
166	for (i = 0; i < type->nNames; i++) {
167		type->procDirs[i] = createProcDir(type->name[i], parent);
168		if (type->procDirs[i] == NULL)
169			RETPTR(NULL);
170		parent = type->procDirs[i];
171	}
172	type->procDir = type->procDirs[type->nNames-1];
173	RETPTR(type);
174Away:
175	if (rc == NULL) {
176		if (type != NULL) {
177			visor_proc_DestroyType(type);
178			type = NULL;
179		}
180	}
181	return rc;
182}
183EXPORT_SYMBOL_GPL(visor_proc_CreateType);
184
185
186
187void visor_proc_DestroyType(MYPROCTYPE *type)
188{
189	if (type == NULL)
190		return;
191	if (type->procDirs != NULL) {
192		int i = type->nNames-1;
193		while (i >= 0) {
194			if (type->procDirs[i] != NULL) {
195				struct proc_dir_entry *parent = NULL;
196				if (i == 0)
197					parent = type->procDirRoot;
198				else
199					parent = type->procDirs[i-1];
200				remove_proc_entry(type->name[i], parent);
201			}
202			i--;
203		}
204		kfree(type->procDirs);
205		type->procDirs = NULL;
206	}
207	kfree(type);
208}
209EXPORT_SYMBOL_GPL(visor_proc_DestroyType);
210
211
212
213MYPROCOBJECT *visor_proc_CreateObject(MYPROCTYPE *type,
214				      const char *name, void *context)
215{
216	MYPROCOBJECT *obj = NULL, *rc = NULL;
217	int i = 0;
218
219	if (type == NULL)
220		FAIL("type cannot be NULL", 0);
221	obj = kmalloc(sizeof(MYPROCOBJECT), GFP_KERNEL | __GFP_NORETRY);
222	if (obj == NULL)
223		FAIL("out of memory", 0);
224	memset(obj, 0, sizeof(MYPROCOBJECT));
225	obj->type = type;
226	obj->context = context;
227	if (name == NULL) {
228		obj->name = NULL;
229		obj->procDir = type->procDir;
230	} else {
231		obj->namesize = strlen(name)+1;
232		obj->name = kmalloc(obj->namesize, GFP_KERNEL | __GFP_NORETRY);
233		if (obj->name == NULL) {
234			obj->namesize = 0;
235			FAIL("out of memory", 0);
236		}
237		strcpy(obj->name, name);
238		obj->procDir = createProcDir(obj->name, type->procDir);
239		if (obj->procDir == NULL)
240			RETPTR(NULL);
241	}
242	obj->procDirPropertyContexts =
243		kmalloc((type->nProperties+1)*sizeof(PROCDIRENTRYCONTEXT),
244			GFP_KERNEL|__GFP_NORETRY);
245	if (obj->procDirPropertyContexts == NULL)
246		FAIL("out of memory", 0);
247	memset(obj->procDirPropertyContexts, 0,
248	       (type->nProperties+1)*sizeof(PROCDIRENTRYCONTEXT));
249	obj->procDirProperties =
250		kmalloc((type->nProperties+1) * sizeof(struct proc_dir_entry *),
251			GFP_KERNEL|__GFP_NORETRY);
252	if (obj->procDirProperties == NULL)
253		FAIL("out of memory", 0);
254	memset(obj->procDirProperties, 0,
255	       (type->nProperties+1) * sizeof(struct proc_dir_entry *));
256	for (i = 0; i < type->nProperties; i++) {
257		obj->procDirPropertyContexts[i].procObject = obj;
258		obj->procDirPropertyContexts[i].propertyIndex = i;
259		obj->procDirPropertyContexts[i].show_property =
260			type->show_property;
261		if (type->propertyNames[i][0] != '\0') {
262			/* only create properties that have names */
263			obj->procDirProperties[i] =
264				createProcFile(type->propertyNames[i],
265					       obj->procDir, &proc_fops,
266					       &obj->procDirPropertyContexts[i]);
267			if (obj->procDirProperties[i] == NULL)
268				RETPTR(NULL);
269		}
270	}
271	RETPTR(obj);
272Away:
273	if (rc == NULL) {
274		if (obj != NULL) {
275			visor_proc_DestroyObject(obj);
276			obj = NULL;
277		}
278	}
279	return rc;
280}
281EXPORT_SYMBOL_GPL(visor_proc_CreateObject);
282
283
284
285void visor_proc_DestroyObject(MYPROCOBJECT *obj)
286{
287	MYPROCTYPE *type = NULL;
288	if (obj == NULL)
289		return;
290	type = obj->type;
291	if (type == NULL)
292		return;
293	if (obj->procDirProperties != NULL) {
294		int i = 0;
295		for (i = 0; i < type->nProperties; i++) {
296			if (obj->procDirProperties[i] != NULL) {
297				remove_proc_entry(type->propertyNames[i],
298						  obj->procDir);
299				obj->procDirProperties[i] = NULL;
300			}
301		}
302		kfree(obj->procDirProperties);
303		obj->procDirProperties = NULL;
304	}
305	if (obj->procDirPropertyContexts != NULL) {
306		kfree(obj->procDirPropertyContexts);
307		obj->procDirPropertyContexts = NULL;
308	}
309	if (obj->procDir != NULL) {
310		if (obj->name != NULL)
311			remove_proc_entry(obj->name, type->procDir);
312		obj->procDir = NULL;
313	}
314	if (obj->name != NULL) {
315		kfree(obj->name);
316		obj->name = NULL;
317	}
318	kfree(obj);
319}
320EXPORT_SYMBOL_GPL(visor_proc_DestroyObject);
321
322
323
324static int seq_show(struct seq_file *seq, void *offset)
325{
326	PROCDIRENTRYCONTEXT *ctx = (PROCDIRENTRYCONTEXT *)(seq->private);
327	if (ctx == NULL) {
328		ERRDRV("I don't have a freakin' clue...");
329		return 0;
330	}
331	(*ctx->show_property)(seq, ctx->procObject->context,
332			      ctx->propertyIndex);
333	return 0;
334}
335