BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file NCDUdevCache.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <stdlib.h>
31 #include <string.h>
32  
33 #include <misc/offset.h>
34 #include <misc/string_begins_with.h>
35 #include <misc/concat_strings.h>
36 #include <misc/compare.h>
37 #include <base/BLog.h>
38  
39 #include <udevmonitor/NCDUdevCache.h>
40  
41 #include <generated/blog_channel_NCDUdevCache.h>
42  
43 static int string_comparator (void *unused, const char **str1, const char **str2)
44 {
45 int c = strcmp(*str1, *str2);
46 return B_COMPARE(c, 0);
47 }
48  
49 static void free_device (NCDUdevCache *o, struct NCDUdevCache_device *device)
50 {
51 if (device->is_cleaned) {
52 // remove from cleaned devices list
53 LinkedList1_Remove(&o->cleaned_devices_list, &device->cleaned_devices_list_node);
54 } else {
55 // remove from devices tree
56 BAVL_Remove(&o->devices_tree, &device->devices_tree_node);
57 }
58  
59 // free map
60 BStringMap_Free(&device->map);
61  
62 // free structure
63 free(device);
64 }
65  
66 static struct NCDUdevCache_device * lookup_device (NCDUdevCache *o, const char *devpath)
67 {
68 BAVLNode *tree_node = BAVL_LookupExact(&o->devices_tree, &devpath);
69 if (!tree_node) {
70 return NULL;
71 }
72 struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
73 ASSERT(!device->is_cleaned)
74  
75 return device;
76 }
77  
78 static void rename_devices (NCDUdevCache *o, const char *prefix, const char *new_prefix)
79 {
80 ASSERT(strlen(prefix) > 0)
81  
82 size_t prefix_len = strlen(prefix);
83  
84 // lookup prefix
85 BAVLNode *tree_node = BAVL_Lookup(&o->devices_tree, &prefix);
86 if (!tree_node) {
87 return;
88 }
89 struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
90 ASSERT(!device->is_cleaned)
91  
92 // if the result does not begin with prefix, we might gave gotten the device before all
93 // devices beginning with prefix, so skip it
94 if (!string_begins_with(device->devpath, prefix)) {
95 tree_node = BAVL_GetNext(&o->devices_tree, tree_node);
96 }
97  
98 while (tree_node) {
99 // get next node (must be here because we rename this device)
100 BAVLNode *next_tree_node = BAVL_GetNext(&o->devices_tree, tree_node);
101  
102 // get device
103 device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
104 ASSERT(!device->is_cleaned)
105  
106 // if it doesn't begin with prefix, we're done
107 if (!string_begins_with(device->devpath, prefix)) {
108 break;
109 }
110  
111 // build new devpath
112 char *new_devpath = concat_strings(2, new_prefix, device->devpath + prefix_len);
113 if (!new_devpath) {
114 BLog(BLOG_ERROR, "concat_strings failed");
115 goto fail_loop0;
116 }
117  
118 // make sure the new name does not exist
119 if (BAVL_LookupExact(&o->devices_tree, &new_devpath)) {
120 BLog(BLOG_ERROR, "rename destination already exists");
121 goto fail_loop1;
122 }
123  
124 BLog(BLOG_DEBUG, "rename %s -> %s", device->devpath, new_devpath);
125  
126 // remove from tree
127 BAVL_Remove(&o->devices_tree, &device->devices_tree_node);
128  
129 // update devpath in map
130 if (!BStringMap_Set(&device->map, "DEVPATH", new_devpath)) {
131 BLog(BLOG_ERROR, "BStringMap_Set failed");
132 ASSERT_EXECUTE(BAVL_Insert(&o->devices_tree, &device->devices_tree_node, NULL))
133 goto fail_loop1;
134 }
135  
136 // update devpath pointer
137 device->devpath = BStringMap_Get(&device->map, "DEVPATH");
138 ASSERT(device->devpath)
139  
140 // insert to tree
141 ASSERT_EXECUTE(BAVL_Insert(&o->devices_tree, &device->devices_tree_node, NULL))
142  
143 fail_loop1:
144 free(new_devpath);
145 fail_loop0:
146 tree_node = next_tree_node;
147 }
148 }
149  
150 static int add_device (NCDUdevCache *o, BStringMap map)
151 {
152 ASSERT(BStringMap_Get(&map, "DEVPATH"))
153  
154 // alloc structure
155 struct NCDUdevCache_device *device = malloc(sizeof(*device));
156 if (!device) {
157 BLog(BLOG_ERROR, "malloc failed");
158 goto fail0;
159 }
160  
161 // init map
162 device->map = map;
163  
164 // set device path
165 device->devpath = BStringMap_Get(&device->map, "DEVPATH");
166  
167 // insert to devices tree
168 BAVLNode *ex_node;
169 if (!BAVL_Insert(&o->devices_tree, &device->devices_tree_node, &ex_node)) {
170 BLog(BLOG_DEBUG, "update %s", device->devpath);
171  
172 // get existing device
173 struct NCDUdevCache_device *ex_device = UPPER_OBJECT(ex_node, struct NCDUdevCache_device, devices_tree_node);
174 ASSERT(!ex_device->is_cleaned)
175  
176 // remove exiting device
177 free_device(o, ex_device);
178  
179 // insert
180 ASSERT_EXECUTE(BAVL_Insert(&o->devices_tree, &device->devices_tree_node, NULL))
181 } else {
182 BLog(BLOG_DEBUG, "add %s", device->devpath);
183 }
184  
185 // set not cleaned
186 device->is_cleaned = 0;
187  
188 // set refreshed
189 device->is_refreshed = 1;
190  
191 return 1;
192  
193 fail0:
194 return 0;
195 }
196  
197 void NCDUdevCache_Init (NCDUdevCache *o)
198 {
199 // init devices tree
200 BAVL_Init(&o->devices_tree, OFFSET_DIFF(struct NCDUdevCache_device, devpath, devices_tree_node), (BAVL_comparator)string_comparator, NULL);
201  
202 // init cleaned devices list
203 LinkedList1_Init(&o->cleaned_devices_list);
204  
205 DebugObject_Init(&o->d_obj);
206 }
207  
208 void NCDUdevCache_Free (NCDUdevCache *o)
209 {
210 DebugObject_Free(&o->d_obj);
211  
212 // free cleaned devices
213 LinkedList1Node *list_node;
214 while (list_node = LinkedList1_GetFirst(&o->cleaned_devices_list)) {
215 struct NCDUdevCache_device *device = UPPER_OBJECT(list_node, struct NCDUdevCache_device, cleaned_devices_list_node);
216 ASSERT(device->is_cleaned)
217 free_device(o, device);
218 }
219  
220 // free devices
221 BAVLNode *tree_node;
222 while (tree_node = BAVL_GetFirst(&o->devices_tree)) {
223 struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
224 ASSERT(!device->is_cleaned)
225 free_device(o, device);
226 }
227 }
228  
229 const BStringMap * NCDUdevCache_Query (NCDUdevCache *o, const char *devpath)
230 {
231 DebugObject_Access(&o->d_obj);
232  
233 // lookup device
234 struct NCDUdevCache_device *device = lookup_device(o, devpath);
235 if (!device) {
236 return NULL;
237 }
238  
239 // return map
240 return &device->map;
241 }
242  
243 int NCDUdevCache_Event (NCDUdevCache *o, BStringMap map)
244 {
245 DebugObject_Access(&o->d_obj);
246  
247 // get device path
248 const char *devpath = BStringMap_Get(&map, "DEVPATH");
249 if (!devpath) {
250 BLog(BLOG_ERROR, "missing DEVPATH");
251 goto fail;
252 }
253  
254 // get action
255 const char *action = BStringMap_Get(&map, "ACTION");
256  
257 // if this is a remove event, remove device if we have it
258 if (action && !strcmp(action, "remove")) {
259 // remove existing device
260 struct NCDUdevCache_device *device = lookup_device(o, devpath);
261 if (device) {
262 BLog(BLOG_DEBUG, "remove %s", devpath);
263 free_device(o, device);
264 } else {
265 BLog(BLOG_DEBUG, "remove unknown %s", devpath);
266 }
267  
268 // eat map
269 BStringMap_Free(&map);
270  
271 return 1;
272 }
273  
274 // if this is a move event, remove old device and contaned devices
275 if (action && !strcmp(action, "move")) {
276 const char *devpath_old = BStringMap_Get(&map, "DEVPATH_OLD");
277 if (!devpath_old) {
278 goto fail_rename0;
279 }
280  
281 // remove old device
282 struct NCDUdevCache_device *old_device = lookup_device(o, devpath_old);
283 if (old_device) {
284 BLog(BLOG_DEBUG, "remove moved %s", old_device->devpath);
285 free_device(o, old_device);
286 }
287  
288 // construct prefix "<devpath_old>/" and new prefix "<devpath>/"
289 char *prefix = concat_strings(2, devpath_old, "/");
290 if (!prefix) {
291 BLog(BLOG_ERROR, "concat_strings failed");
292 goto fail_rename0;;
293 }
294 char *new_prefix = concat_strings(2, devpath, "/");
295 if (!new_prefix) {
296 BLog(BLOG_ERROR, "concat_strings failed");
297 goto fail_rename1;
298 }
299  
300 // rename devices with paths starting with prefix
301 rename_devices(o, prefix, new_prefix);
302  
303 free(new_prefix);
304 fail_rename1:
305 free(prefix);
306 fail_rename0:;
307 }
308  
309 // add device
310 if (!add_device(o, map)) {
311 BLog(BLOG_DEBUG, "failed to add device %s", devpath);
312 goto fail;
313 }
314  
315 return 1;
316  
317 fail:
318 return 0;
319 }
320  
321 void NCDUdevCache_StartClean (NCDUdevCache *o)
322 {
323 DebugObject_Access(&o->d_obj);
324  
325 // mark all devices not refreshed
326 BAVLNode *tree_node = BAVL_GetFirst(&o->devices_tree);
327 while (tree_node) {
328 struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
329 ASSERT(!device->is_cleaned)
330  
331 // set device not refreshed
332 device->is_refreshed = 0;
333  
334 tree_node = BAVL_GetNext(&o->devices_tree, tree_node);
335 }
336 }
337  
338 void NCDUdevCache_FinishClean (NCDUdevCache *o)
339 {
340 DebugObject_Access(&o->d_obj);
341  
342 // move all devices not marked refreshed to the cleaned devices list
343 BAVLNode *tree_node = BAVL_GetFirst(&o->devices_tree);
344 while (tree_node) {
345 BAVLNode *next_tree_node = BAVL_GetNext(&o->devices_tree, tree_node);
346  
347 struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
348 ASSERT(!device->is_cleaned)
349  
350 if (!device->is_refreshed) {
351 BLog(BLOG_DEBUG, "clean %s", device->devpath);
352  
353 // remove from devices tree
354 BAVL_Remove(&o->devices_tree, &device->devices_tree_node);
355  
356 // insert to cleaned devices list
357 LinkedList1_Append(&o->cleaned_devices_list, &device->cleaned_devices_list_node);
358  
359 // set device cleaned
360 device->is_cleaned = 1;
361 }
362  
363 tree_node = next_tree_node;
364 }
365 }
366  
367 int NCDUdevCache_GetCleanedDevice (NCDUdevCache *o, BStringMap *out_map)
368 {
369 DebugObject_Access(&o->d_obj);
370  
371 // get cleaned device
372 LinkedList1Node *list_node = LinkedList1_GetFirst(&o->cleaned_devices_list);
373 if (!list_node) {
374 return 0;
375 }
376 struct NCDUdevCache_device *device = UPPER_OBJECT(list_node, struct NCDUdevCache_device, cleaned_devices_list_node);
377 ASSERT(device->is_cleaned)
378  
379 // remove from cleaned devices list
380 LinkedList1_Remove(&o->cleaned_devices_list, &device->cleaned_devices_list_node);
381  
382 // give away map
383 *out_map = device->map;
384  
385 // free structure
386 free(device);
387  
388 return 1;
389 }
390  
391 const char * NCDUdevCache_First (NCDUdevCache *o)
392 {
393 DebugObject_Access(&o->d_obj);
394  
395 BAVLNode *tree_node = BAVL_GetFirst(&o->devices_tree);
396 if (!tree_node) {
397 return NULL;
398 }
399 struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
400 ASSERT(!device->is_cleaned)
401  
402 return device->devpath;
403 }
404  
405 const char * NCDUdevCache_Next (NCDUdevCache *o, const char *key)
406 {
407 ASSERT(BAVL_LookupExact(&o->devices_tree, &key))
408  
409 BAVLNode *tree_node = BAVL_GetNext(&o->devices_tree, BAVL_LookupExact(&o->devices_tree, &key));
410 if (!tree_node) {
411 return NULL;
412 }
413 struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
414 ASSERT(!device->is_cleaned)
415  
416 return device->devpath;
417 }