| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- /**
- * @file NCDUdevCache.c
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- *
- * @section LICENSE
- *
- * This file is part of BadVPN.
- *
- * BadVPN is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * BadVPN is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- #include <stdlib.h>
- #include <string.h>
- #include <misc/offset.h>
- #include <misc/string_begins_with.h>
- #include <misc/concat_strings.h>
- #include <base/BLog.h>
- #include <udevmonitor/NCDUdevCache.h>
- #include <generated/blog_channel_NCDUdevCache.h>
- static int string_comparator (void *unused, const char **str1, const char **str2)
- {
- int c = strcmp(*str1, *str2);
- if (c < 0) {
- return -1;
- }
- if (c > 0) {
- return 1;
- }
- return 0;
- }
- static void free_device (NCDUdevCache *o, struct NCDUdevCache_device *device)
- {
- if (device->is_cleaned) {
- // remove from cleaned devices list
- LinkedList1_Remove(&o->cleaned_devices_list, &device->cleaned_devices_list_node);
- } else {
- // remove from devices tree
- BAVL_Remove(&o->devices_tree, &device->devices_tree_node);
- }
-
- // free map
- BStringMap_Free(&device->map);
-
- // free structure
- free(device);
- }
- static struct NCDUdevCache_device * lookup_device (NCDUdevCache *o, const char *devpath)
- {
- BAVLNode *tree_node = BAVL_LookupExact(&o->devices_tree, &devpath);
- if (!tree_node) {
- return NULL;
- }
- struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
- ASSERT(!device->is_cleaned)
-
- return device;
- }
- static void rename_devices (NCDUdevCache *o, const char *prefix, const char *new_prefix)
- {
- ASSERT(strlen(prefix) > 0)
-
- size_t prefix_len = strlen(prefix);
-
- // lookup prefix
- BAVLNode *tree_node = BAVL_Lookup(&o->devices_tree, &prefix);
- if (!tree_node) {
- return;
- }
- struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
- ASSERT(!device->is_cleaned)
-
- // if the result does not begin with prefix, we might gave gotten the device before all
- // devices beginning with prefix, so skip it
- if (!string_begins_with(device->devpath, prefix)) {
- tree_node = BAVL_GetNext(&o->devices_tree, tree_node);
- }
-
- while (tree_node) {
- // get next node (must be here because we rename this device)
- BAVLNode *next_tree_node = BAVL_GetNext(&o->devices_tree, tree_node);
-
- // get device
- device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
- ASSERT(!device->is_cleaned)
-
- // if it doesn't begin with prefix, we're done
- if (!string_begins_with(device->devpath, prefix)) {
- break;
- }
-
- // build new devpath
- char *new_devpath = concat_strings(2, new_prefix, device->devpath + prefix_len);
- if (!new_devpath) {
- BLog(BLOG_ERROR, "concat_strings failed");
- goto fail_loop0;
- }
-
- // make sure the new name does not exist
- if (BAVL_LookupExact(&o->devices_tree, &new_devpath)) {
- BLog(BLOG_ERROR, "rename destination already exists");
- goto fail_loop1;
- }
-
- BLog(BLOG_DEBUG, "rename %s -> %s", device->devpath, new_devpath);
-
- // remove from tree
- BAVL_Remove(&o->devices_tree, &device->devices_tree_node);
-
- // update devpath in map
- if (!BStringMap_Set(&device->map, "DEVPATH", new_devpath)) {
- BLog(BLOG_ERROR, "BStringMap_Set failed");
- ASSERT_EXECUTE(BAVL_Insert(&o->devices_tree, &device->devices_tree_node, NULL))
- goto fail_loop1;
- }
-
- // update devpath pointer
- device->devpath = BStringMap_Get(&device->map, "DEVPATH");
- ASSERT(device->devpath)
-
- // insert to tree
- ASSERT_EXECUTE(BAVL_Insert(&o->devices_tree, &device->devices_tree_node, NULL))
-
- fail_loop1:
- free(new_devpath);
- fail_loop0:
- tree_node = next_tree_node;
- }
- }
- static int add_device (NCDUdevCache *o, BStringMap map)
- {
- ASSERT(BStringMap_Get(&map, "DEVPATH"))
-
- // alloc structure
- struct NCDUdevCache_device *device = malloc(sizeof(*device));
- if (!device) {
- BLog(BLOG_ERROR, "malloc failed");
- goto fail0;
- }
-
- // init map
- device->map = map;
-
- // set device path
- device->devpath = BStringMap_Get(&device->map, "DEVPATH");
-
- // insert to devices tree
- BAVLNode *ex_node;
- if (!BAVL_Insert(&o->devices_tree, &device->devices_tree_node, &ex_node)) {
- BLog(BLOG_DEBUG, "update %s", device->devpath);
-
- // get existing device
- struct NCDUdevCache_device *ex_device = UPPER_OBJECT(ex_node, struct NCDUdevCache_device, devices_tree_node);
- ASSERT(!ex_device->is_cleaned)
-
- // remove exiting device
- free_device(o, ex_device);
-
- // insert
- ASSERT_EXECUTE(BAVL_Insert(&o->devices_tree, &device->devices_tree_node, NULL))
- } else {
- BLog(BLOG_DEBUG, "add %s", device->devpath);
- }
-
- // set not cleaned
- device->is_cleaned = 0;
-
- // set refreshed
- device->is_refreshed = 1;
-
- return 1;
-
- fail0:
- return 0;
- }
- void NCDUdevCache_Init (NCDUdevCache *o)
- {
- // init devices tree
- BAVL_Init(&o->devices_tree, OFFSET_DIFF(struct NCDUdevCache_device, devpath, devices_tree_node), (BAVL_comparator)string_comparator, NULL);
-
- // init cleaned devices list
- LinkedList1_Init(&o->cleaned_devices_list);
-
- DebugObject_Init(&o->d_obj);
- }
- void NCDUdevCache_Free (NCDUdevCache *o)
- {
- DebugObject_Free(&o->d_obj);
-
- // free cleaned devices
- LinkedList1Node *list_node;
- while (list_node = LinkedList1_GetFirst(&o->cleaned_devices_list)) {
- struct NCDUdevCache_device *device = UPPER_OBJECT(list_node, struct NCDUdevCache_device, cleaned_devices_list_node);
- ASSERT(device->is_cleaned)
- free_device(o, device);
- }
-
- // free devices
- BAVLNode *tree_node;
- while (tree_node = BAVL_GetFirst(&o->devices_tree)) {
- struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
- ASSERT(!device->is_cleaned)
- free_device(o, device);
- }
- }
- const BStringMap * NCDUdevCache_Query (NCDUdevCache *o, const char *devpath)
- {
- DebugObject_Access(&o->d_obj);
-
- // lookup device
- struct NCDUdevCache_device *device = lookup_device(o, devpath);
- if (!device) {
- return NULL;
- }
-
- // return map
- return &device->map;
- }
- int NCDUdevCache_Event (NCDUdevCache *o, BStringMap map)
- {
- DebugObject_Access(&o->d_obj);
-
- // get device path
- const char *devpath = BStringMap_Get(&map, "DEVPATH");
- if (!devpath) {
- BLog(BLOG_ERROR, "missing DEVPATH");
- goto fail;
- }
-
- // get action
- const char *action = BStringMap_Get(&map, "ACTION");
-
- // if this is a remove event, remove device if we have it
- if (action && !strcmp(action, "remove")) {
- // remove existing device
- struct NCDUdevCache_device *device = lookup_device(o, devpath);
- if (device) {
- BLog(BLOG_DEBUG, "remove %s", devpath);
- free_device(o, device);
- } else {
- BLog(BLOG_DEBUG, "remove unknown %s", devpath);
- }
-
- // eat map
- BStringMap_Free(&map);
-
- return 1;
- }
-
- // if this is a move event, remove old device and contaned devices
- if (action && !strcmp(action, "move")) {
- const char *devpath_old = BStringMap_Get(&map, "DEVPATH_OLD");
- if (!devpath_old) {
- goto fail_rename0;
- }
-
- // remove old device
- struct NCDUdevCache_device *old_device = lookup_device(o, devpath_old);
- if (old_device) {
- BLog(BLOG_DEBUG, "remove moved %s", old_device->devpath);
- free_device(o, old_device);
- }
-
- // construct prefix "<devpath_old>/" and new prefix "<devpath>/"
- char *prefix = concat_strings(2, devpath_old, "/");
- if (!prefix) {
- BLog(BLOG_ERROR, "concat_strings failed");
- goto fail_rename0;;
- }
- char *new_prefix = concat_strings(2, devpath, "/");
- if (!new_prefix) {
- BLog(BLOG_ERROR, "concat_strings failed");
- goto fail_rename1;
- }
-
- // rename devices with paths starting with prefix
- rename_devices(o, prefix, new_prefix);
-
- free(new_prefix);
- fail_rename1:
- free(prefix);
- fail_rename0:;
- }
-
- // add device
- if (!add_device(o, map)) {
- BLog(BLOG_DEBUG, "failed to add device %s", devpath);
- goto fail;
- }
-
- return 1;
-
- fail:
- return 0;
- }
- void NCDUdevCache_StartClean (NCDUdevCache *o)
- {
- DebugObject_Access(&o->d_obj);
-
- // mark all devices not refreshed
- BAVLNode *tree_node = BAVL_GetFirst(&o->devices_tree);
- while (tree_node) {
- struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
- ASSERT(!device->is_cleaned)
-
- // set device not refreshed
- device->is_refreshed = 0;
-
- tree_node = BAVL_GetNext(&o->devices_tree, tree_node);
- }
- }
- void NCDUdevCache_FinishClean (NCDUdevCache *o)
- {
- DebugObject_Access(&o->d_obj);
-
- // move all devices not marked refreshed to the cleaned devices list
- BAVLNode *tree_node = BAVL_GetFirst(&o->devices_tree);
- while (tree_node) {
- BAVLNode *next_tree_node = BAVL_GetNext(&o->devices_tree, tree_node);
-
- struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
- ASSERT(!device->is_cleaned)
-
- if (!device->is_refreshed) {
- BLog(BLOG_DEBUG, "clean %s", device->devpath);
-
- // remove from devices tree
- BAVL_Remove(&o->devices_tree, &device->devices_tree_node);
-
- // insert to cleaned devices list
- LinkedList1_Append(&o->cleaned_devices_list, &device->cleaned_devices_list_node);
-
- // set device cleaned
- device->is_cleaned = 1;
- }
-
- tree_node = next_tree_node;
- }
- }
- int NCDUdevCache_GetCleanedDevice (NCDUdevCache *o, BStringMap *out_map)
- {
- DebugObject_Access(&o->d_obj);
-
- // get cleaned device
- LinkedList1Node *list_node = LinkedList1_GetFirst(&o->cleaned_devices_list);
- if (!list_node) {
- return 0;
- }
- struct NCDUdevCache_device *device = UPPER_OBJECT(list_node, struct NCDUdevCache_device, cleaned_devices_list_node);
- ASSERT(device->is_cleaned)
-
- // remove from cleaned devices list
- LinkedList1_Remove(&o->cleaned_devices_list, &device->cleaned_devices_list_node);
-
- // give away map
- *out_map = device->map;
-
- // free structure
- free(device);
-
- return 1;
- }
- const char * NCDUdevCache_First (NCDUdevCache *o)
- {
- DebugObject_Access(&o->d_obj);
-
- BAVLNode *tree_node = BAVL_GetFirst(&o->devices_tree);
- if (!tree_node) {
- return NULL;
- }
- struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
- ASSERT(!device->is_cleaned)
-
- return device->devpath;
- }
- const char * NCDUdevCache_Next (NCDUdevCache *o, const char *key)
- {
- ASSERT(BAVL_LookupExact(&o->devices_tree, &key))
-
- BAVLNode *tree_node = BAVL_GetNext(&o->devices_tree, BAVL_LookupExact(&o->devices_tree, &key));
- if (!tree_node) {
- return NULL;
- }
- struct NCDUdevCache_device *device = UPPER_OBJECT(tree_node, struct NCDUdevCache_device, devices_tree_node);
- ASSERT(!device->is_cleaned)
-
- return device->devpath;
- }
|