• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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