|
@@ -0,0 +1,535 @@
|
|
|
|
|
+/**
|
|
|
|
|
+ * @file NCDUdevManager.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 <system/BLog.h>
|
|
|
|
|
+
|
|
|
|
|
+#include <udevmonitor/NCDUdevManager.h>
|
|
|
|
|
+
|
|
|
|
|
+#include <generated/blog_channel_NCDUdevManager.h>
|
|
|
|
|
+
|
|
|
|
|
+#define RESTART_TIMER_TIME 5000
|
|
|
|
|
+
|
|
|
|
|
+static int event_to_map (NCDUdevMonitor *monitor, BStringMap *out_map);
|
|
|
|
|
+static void free_event (NCDUdevClient *o, struct NCDUdevClient_event *e);
|
|
|
|
|
+static void queue_event (NCDUdevManager *o, NCDUdevMonitor *monitor, NCDUdevClient *client);
|
|
|
|
|
+static void queue_mapless_event (NCDUdevManager *o, const char *devpath, NCDUdevClient *client);
|
|
|
|
|
+static void process_event (NCDUdevManager *o, NCDUdevMonitor *monitor);
|
|
|
|
|
+static void try_monitor (NCDUdevManager *o);
|
|
|
|
|
+static void reset_monitor (NCDUdevManager *o);
|
|
|
|
|
+static void timer_handler (NCDUdevManager *o);
|
|
|
|
|
+static void monitor_handler_event (NCDUdevManager *o);
|
|
|
|
|
+static void monitor_handler_error (NCDUdevManager *o, int is_error);
|
|
|
|
|
+static void info_monitor_handler_event (NCDUdevManager *o);
|
|
|
|
|
+static void info_monitor_handler_error (NCDUdevManager *o, int is_error);
|
|
|
|
|
+static void next_job_handler (NCDUdevClient *o);
|
|
|
|
|
+
|
|
|
|
|
+static int event_to_map (NCDUdevMonitor *monitor, BStringMap *out_map)
|
|
|
|
|
+{
|
|
|
|
|
+ NCDUdevMonitor_AssertReady(monitor);
|
|
|
|
|
+
|
|
|
|
|
+ // init map
|
|
|
|
|
+ BStringMap_Init(out_map);
|
|
|
|
|
+
|
|
|
|
|
+ // insert properties to map
|
|
|
|
|
+ int num_properties = NCDUdevMonitor_GetNumProperties(monitor);
|
|
|
|
|
+ for (int i = 0; i < num_properties; i++) {
|
|
|
|
|
+ const char *name;
|
|
|
|
|
+ const char *value;
|
|
|
|
|
+ NCDUdevMonitor_GetProperty(monitor, i, &name, &value);
|
|
|
|
|
+
|
|
|
|
|
+ if (!BStringMap_Set(out_map, name, value)) {
|
|
|
|
|
+ BLog(BLOG_ERROR, "BStringMap_Set failed");
|
|
|
|
|
+ goto fail1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 1;
|
|
|
|
|
+
|
|
|
|
|
+fail1:
|
|
|
|
|
+ BStringMap_Free(out_map);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void free_event (NCDUdevClient *o, struct NCDUdevClient_event *e)
|
|
|
|
|
+{
|
|
|
|
|
+ // remove from events list
|
|
|
|
|
+ LinkedList1_Remove(&o->events_list, &e->events_list_node);
|
|
|
|
|
+
|
|
|
|
|
+ // free map
|
|
|
|
|
+ if (e->have_map) {
|
|
|
|
|
+ BStringMap_Free(&e->map);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // free devpath
|
|
|
|
|
+ free(e->devpath);
|
|
|
|
|
+
|
|
|
|
|
+ // free structure
|
|
|
|
|
+ free(e);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void queue_event (NCDUdevManager *o, NCDUdevMonitor *monitor, NCDUdevClient *client)
|
|
|
|
|
+{
|
|
|
|
|
+ NCDUdevMonitor_AssertReady(monitor);
|
|
|
|
|
+
|
|
|
|
|
+ // alloc event
|
|
|
|
|
+ struct NCDUdevClient_event *e = malloc(sizeof(*e));
|
|
|
|
|
+ if (!e) {
|
|
|
|
|
+ BLog(BLOG_ERROR, "malloc failed");
|
|
|
|
|
+ goto fail0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // build map
|
|
|
|
|
+ if (!event_to_map(monitor, &e->map)) {
|
|
|
|
|
+ goto fail1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // set have map
|
|
|
|
|
+ e->have_map = 1;
|
|
|
|
|
+
|
|
|
|
|
+ // get devpath
|
|
|
|
|
+ const char *devpath = BStringMap_Get(&e->map, "DEVPATH");
|
|
|
|
|
+ if (!devpath) {
|
|
|
|
|
+ BLog(BLOG_ERROR, "DEVPATH missing");
|
|
|
|
|
+ goto fail2;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // copy devpath
|
|
|
|
|
+ if (!(e->devpath = strdup(devpath))) {
|
|
|
|
|
+ BLog(BLOG_ERROR, "strdup failed");
|
|
|
|
|
+ goto fail2;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // insert to client's events list
|
|
|
|
|
+ LinkedList1_Append(&client->events_list, &e->events_list_node);
|
|
|
|
|
+
|
|
|
|
|
+ // if client is running, set next job
|
|
|
|
|
+ if (client->running) {
|
|
|
|
|
+ BPending_Set(&client->next_job);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+fail2:
|
|
|
|
|
+ BStringMap_Free(&e->map);
|
|
|
|
|
+fail1:
|
|
|
|
|
+ free(e);
|
|
|
|
|
+fail0:
|
|
|
|
|
+ return;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void queue_mapless_event (NCDUdevManager *o, const char *devpath, NCDUdevClient *client)
|
|
|
|
|
+{
|
|
|
|
|
+ // alloc event
|
|
|
|
|
+ struct NCDUdevClient_event *e = malloc(sizeof(*e));
|
|
|
|
|
+ if (!e) {
|
|
|
|
|
+ BLog(BLOG_ERROR, "malloc failed");
|
|
|
|
|
+ goto fail0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // set have no map
|
|
|
|
|
+ e->have_map = 0;
|
|
|
|
|
+
|
|
|
|
|
+ // copy devpath
|
|
|
|
|
+ if (!(e->devpath = strdup(devpath))) {
|
|
|
|
|
+ BLog(BLOG_ERROR, "strdup failed");
|
|
|
|
|
+ goto fail1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // insert to client's events list
|
|
|
|
|
+ LinkedList1_Append(&client->events_list, &e->events_list_node);
|
|
|
|
|
+
|
|
|
|
|
+ // if client is running, set next job
|
|
|
|
|
+ if (client->running) {
|
|
|
|
|
+ BPending_Set(&client->next_job);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+fail1:
|
|
|
|
|
+ free(e);
|
|
|
|
|
+fail0:
|
|
|
|
|
+ return;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void process_event (NCDUdevManager *o, NCDUdevMonitor *monitor)
|
|
|
|
|
+{
|
|
|
|
|
+ NCDUdevMonitor_AssertReady(monitor);
|
|
|
|
|
+
|
|
|
|
|
+ // build map from event
|
|
|
|
|
+ BStringMap map;
|
|
|
|
|
+ if (!event_to_map(monitor, &map)) {
|
|
|
|
|
+ BLog(BLOG_ERROR, "failed to build map");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // pass event to cache
|
|
|
|
|
+ if (!NCDUdevCache_Event(&o->cache, map)) {
|
|
|
|
|
+ BLog(BLOG_ERROR, "failed to cache");
|
|
|
|
|
+ BStringMap_Free(&map);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // queue event to clients
|
|
|
|
|
+ LinkedList1Node *list_node = LinkedList1_GetFirst(&o->clients_list);
|
|
|
|
|
+ while (list_node) {
|
|
|
|
|
+ NCDUdevClient *client = UPPER_OBJECT(list_node, NCDUdevClient, clients_list_node);
|
|
|
|
|
+ queue_event(o, monitor, client);
|
|
|
|
|
+ list_node = LinkedList1Node_Next(list_node);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void try_monitor (NCDUdevManager *o)
|
|
|
|
|
+{
|
|
|
|
|
+ ASSERT(!o->have_monitor)
|
|
|
|
|
+ ASSERT(!BTimer_IsRunning(&o->restart_timer))
|
|
|
|
|
+
|
|
|
|
|
+ // init monitor
|
|
|
|
|
+ if (!NCDUdevMonitor_Init(&o->monitor, o->reactor, o->manager, 0, o,
|
|
|
|
|
+ (NCDUdevMonitor_handler_event)monitor_handler_event,
|
|
|
|
|
+ (NCDUdevMonitor_handler_error)monitor_handler_error
|
|
|
|
|
+ )) {
|
|
|
|
|
+ BLog(BLOG_ERROR, "NCDUdevMonitor_Init failed");
|
|
|
|
|
+
|
|
|
|
|
+ // set restart timer
|
|
|
|
|
+ BReactor_SetTimer(o->reactor, &o->restart_timer);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // set have monitor
|
|
|
|
|
+ o->have_monitor = 1;
|
|
|
|
|
+
|
|
|
|
|
+ // set not have info monitor
|
|
|
|
|
+ o->have_info_monitor = 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void reset_monitor (NCDUdevManager *o)
|
|
|
|
|
+{
|
|
|
|
|
+ ASSERT(o->have_monitor)
|
|
|
|
|
+ ASSERT(!o->have_info_monitor)
|
|
|
|
|
+ ASSERT(!BTimer_IsRunning(&o->restart_timer))
|
|
|
|
|
+
|
|
|
|
|
+ // free monitor
|
|
|
|
|
+ NCDUdevMonitor_Free(&o->monitor);
|
|
|
|
|
+
|
|
|
|
|
+ // set have no monitor
|
|
|
|
|
+ o->have_monitor = 0;
|
|
|
|
|
+
|
|
|
|
|
+ // set restart timer
|
|
|
|
|
+ BReactor_SetTimer(o->reactor, &o->restart_timer);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void timer_handler (NCDUdevManager *o)
|
|
|
|
|
+{
|
|
|
|
|
+ DebugObject_Access(&o->d_obj);
|
|
|
|
|
+ ASSERT(!o->have_monitor)
|
|
|
|
|
+
|
|
|
|
|
+ // try again
|
|
|
|
|
+ try_monitor(o);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void monitor_handler_event (NCDUdevManager *o)
|
|
|
|
|
+{
|
|
|
|
|
+ DebugObject_Access(&o->d_obj);
|
|
|
|
|
+ ASSERT(o->have_monitor)
|
|
|
|
|
+ ASSERT(!o->have_info_monitor)
|
|
|
|
|
+ ASSERT(!BTimer_IsRunning(&o->restart_timer))
|
|
|
|
|
+
|
|
|
|
|
+ if (NCDUdevMonitor_IsReadyEvent(&o->monitor)) {
|
|
|
|
|
+ BLog(BLOG_INFO, "monitor ready");
|
|
|
|
|
+
|
|
|
|
|
+ // init info monitor
|
|
|
|
|
+ if (!NCDUdevMonitor_Init(&o->info_monitor, o->reactor, o->manager, 1, o,
|
|
|
|
|
+ (NCDUdevMonitor_handler_event)info_monitor_handler_event,
|
|
|
|
|
+ (NCDUdevMonitor_handler_error)info_monitor_handler_error
|
|
|
|
|
+ )) {
|
|
|
|
|
+ BLog(BLOG_ERROR, "NCDUdevMonitor_Init failed");
|
|
|
|
|
+ reset_monitor(o);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // set have info monitor
|
|
|
|
|
+ o->have_info_monitor = 1;
|
|
|
|
|
+
|
|
|
|
|
+ // start cache cleanup
|
|
|
|
|
+ NCDUdevCache_StartClean(&o->cache);
|
|
|
|
|
+
|
|
|
|
|
+ // hold processing monitor events until info monitor is done
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // accept event
|
|
|
|
|
+ NCDUdevMonitor_Done(&o->monitor);
|
|
|
|
|
+
|
|
|
|
|
+ // process event
|
|
|
|
|
+ process_event(o, &o->monitor);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void monitor_handler_error (NCDUdevManager *o, int is_error)
|
|
|
|
|
+{
|
|
|
|
|
+ DebugObject_Access(&o->d_obj);
|
|
|
|
|
+ ASSERT(o->have_monitor)
|
|
|
|
|
+ ASSERT(!BTimer_IsRunning(&o->restart_timer))
|
|
|
|
|
+
|
|
|
|
|
+ BLog(BLOG_ERROR, "monitor error");
|
|
|
|
|
+
|
|
|
|
|
+ if (o->have_info_monitor) {
|
|
|
|
|
+ // free info monitor
|
|
|
|
|
+ NCDUdevMonitor_Free(&o->info_monitor);
|
|
|
|
|
+
|
|
|
|
|
+ // set have no info monitor
|
|
|
|
|
+ o->have_info_monitor = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // reset monitor
|
|
|
|
|
+ reset_monitor(o);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void info_monitor_handler_event (NCDUdevManager *o)
|
|
|
|
|
+{
|
|
|
|
|
+ DebugObject_Access(&o->d_obj);
|
|
|
|
|
+ ASSERT(o->have_monitor)
|
|
|
|
|
+ ASSERT(o->have_info_monitor)
|
|
|
|
|
+ ASSERT(!BTimer_IsRunning(&o->restart_timer))
|
|
|
|
|
+
|
|
|
|
|
+ // accept event
|
|
|
|
|
+ NCDUdevMonitor_Done(&o->info_monitor);
|
|
|
|
|
+
|
|
|
|
|
+ // process event
|
|
|
|
|
+ process_event(o, &o->info_monitor);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void info_monitor_handler_error (NCDUdevManager *o, int is_error)
|
|
|
|
|
+{
|
|
|
|
|
+ DebugObject_Access(&o->d_obj);
|
|
|
|
|
+ ASSERT(o->have_monitor)
|
|
|
|
|
+ ASSERT(o->have_info_monitor)
|
|
|
|
|
+ ASSERT(!BTimer_IsRunning(&o->restart_timer))
|
|
|
|
|
+
|
|
|
|
|
+ if (is_error) {
|
|
|
|
|
+ BLog(BLOG_ERROR, "info monitor error");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ BLog(BLOG_INFO, "info monitor finished");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // free info monitor
|
|
|
|
|
+ NCDUdevMonitor_Free(&o->info_monitor);
|
|
|
|
|
+
|
|
|
|
|
+ // set have no info monitor
|
|
|
|
|
+ o->have_info_monitor = 0;
|
|
|
|
|
+
|
|
|
|
|
+ if (is_error) {
|
|
|
|
|
+ // reset monitor
|
|
|
|
|
+ reset_monitor(o);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // continue processing monitor events
|
|
|
|
|
+ NCDUdevMonitor_Done(&o->monitor);
|
|
|
|
|
+
|
|
|
|
|
+ // finish cache cleanup
|
|
|
|
|
+ NCDUdevCache_FinishClean(&o->cache);
|
|
|
|
|
+
|
|
|
|
|
+ // collect cleaned devices
|
|
|
|
|
+ BStringMap map;
|
|
|
|
|
+ while (NCDUdevCache_GetCleanedDevice(&o->cache, &map)) {
|
|
|
|
|
+ // get devpath
|
|
|
|
|
+ const char *devpath = BStringMap_Get(&map, "DEVPATH");
|
|
|
|
|
+ ASSERT(devpath)
|
|
|
|
|
+
|
|
|
|
|
+ // queue mapless event to clients
|
|
|
|
|
+ LinkedList1Node *list_node = LinkedList1_GetFirst(&o->clients_list);
|
|
|
|
|
+ while (list_node) {
|
|
|
|
|
+ NCDUdevClient *client = UPPER_OBJECT(list_node, NCDUdevClient, clients_list_node);
|
|
|
|
|
+ queue_mapless_event(o, devpath, client);
|
|
|
|
|
+ list_node = LinkedList1Node_Next(list_node);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ BStringMap_Free(&map);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void next_job_handler (NCDUdevClient *o)
|
|
|
|
|
+{
|
|
|
|
|
+ DebugObject_Access(&o->d_obj);
|
|
|
|
|
+ ASSERT(!LinkedList1_IsEmpty(&o->events_list))
|
|
|
|
|
+ ASSERT(o->running)
|
|
|
|
|
+
|
|
|
|
|
+ // get event
|
|
|
|
|
+ struct NCDUdevClient_event *e = UPPER_OBJECT(LinkedList1_GetFirst(&o->events_list), struct NCDUdevClient_event, events_list_node);
|
|
|
|
|
+
|
|
|
|
|
+ // grab map from event
|
|
|
|
|
+ int have_map = e->have_map;
|
|
|
|
|
+ BStringMap map = e->map;
|
|
|
|
|
+
|
|
|
|
|
+ // grab devpath from event
|
|
|
|
|
+ char *devpath = e->devpath;
|
|
|
|
|
+
|
|
|
|
|
+ // remove from events list
|
|
|
|
|
+ LinkedList1_Remove(&o->events_list, &e->events_list_node);
|
|
|
|
|
+
|
|
|
|
|
+ // free structure
|
|
|
|
|
+ free(e);
|
|
|
|
|
+
|
|
|
|
|
+ // schedule next event if needed
|
|
|
|
|
+ if (!LinkedList1_IsEmpty(&o->events_list)) {
|
|
|
|
|
+ BPending_Set(&o->next_job);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // give map to handler
|
|
|
|
|
+ o->handler(o->user, devpath, have_map, map);
|
|
|
|
|
+ return;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void NCDUdevManager_Init (NCDUdevManager *o, BReactor *reactor, BProcessManager *manager)
|
|
|
|
|
+{
|
|
|
|
|
+ // init arguments
|
|
|
|
|
+ o->reactor = reactor;
|
|
|
|
|
+ o->manager = manager;
|
|
|
|
|
+
|
|
|
|
|
+ // init clients list
|
|
|
|
|
+ LinkedList1_Init(&o->clients_list);
|
|
|
|
|
+
|
|
|
|
|
+ // init cache
|
|
|
|
|
+ NCDUdevCache_Init(&o->cache);
|
|
|
|
|
+
|
|
|
|
|
+ // init restart timer
|
|
|
|
|
+ BTimer_Init(&o->restart_timer, RESTART_TIMER_TIME, (BTimer_handler)timer_handler, o);
|
|
|
|
|
+
|
|
|
|
|
+ // set have no monitor
|
|
|
|
|
+ o->have_monitor = 0;
|
|
|
|
|
+
|
|
|
|
|
+ DebugObject_Init(&o->d_obj);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void NCDUdevManager_Free (NCDUdevManager *o)
|
|
|
|
|
+{
|
|
|
|
|
+ DebugObject_Free(&o->d_obj);
|
|
|
|
|
+ ASSERT(LinkedList1_IsEmpty(&o->clients_list))
|
|
|
|
|
+
|
|
|
|
|
+ if (o->have_monitor) {
|
|
|
|
|
+ // free info monitor
|
|
|
|
|
+ if (o->have_info_monitor) {
|
|
|
|
|
+ NCDUdevMonitor_Free(&o->info_monitor);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // free monitor
|
|
|
|
|
+ NCDUdevMonitor_Free(&o->monitor);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // free restart timer
|
|
|
|
|
+ BReactor_RemoveTimer(o->reactor, &o->restart_timer);
|
|
|
|
|
+
|
|
|
|
|
+ // free cache
|
|
|
|
|
+ NCDUdevCache_Free(&o->cache);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const BStringMap * NCDUdevManager_Query (NCDUdevManager *o, const char *devpath)
|
|
|
|
|
+{
|
|
|
|
|
+ DebugObject_Access(&o->d_obj);
|
|
|
|
|
+
|
|
|
|
|
+ return NCDUdevCache_Query(&o->cache, devpath);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void NCDUdevClient_Init (NCDUdevClient *o, NCDUdevManager *m, void *user,
|
|
|
|
|
+ NCDUdevClient_handler handler)
|
|
|
|
|
+{
|
|
|
|
|
+ DebugObject_Access(&m->d_obj);
|
|
|
|
|
+
|
|
|
|
|
+ // init arguments
|
|
|
|
|
+ o->m = m;
|
|
|
|
|
+ o->user = user;
|
|
|
|
|
+ o->handler = handler;
|
|
|
|
|
+
|
|
|
|
|
+ // insert to manager's list
|
|
|
|
|
+ LinkedList1_Append(&m->clients_list, &o->clients_list_node);
|
|
|
|
|
+
|
|
|
|
|
+ // init events list
|
|
|
|
|
+ LinkedList1_Init(&o->events_list);
|
|
|
|
|
+
|
|
|
|
|
+ // init next job
|
|
|
|
|
+ BPending_Init(&o->next_job, BReactor_PendingGroup(m->reactor), (BPending_handler)next_job_handler, o);
|
|
|
|
|
+
|
|
|
|
|
+ // set running
|
|
|
|
|
+ o->running = 1;
|
|
|
|
|
+
|
|
|
|
|
+ // queue all devices from cache
|
|
|
|
|
+ const char *devpath = NCDUdevCache_First(&m->cache);
|
|
|
|
|
+ while (devpath) {
|
|
|
|
|
+ queue_mapless_event(m, devpath, o);
|
|
|
|
|
+ devpath = NCDUdevCache_Next(&m->cache, devpath);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // if this is the first client, init monitor
|
|
|
|
|
+ if (!m->have_monitor && !BTimer_IsRunning(&m->restart_timer)) {
|
|
|
|
|
+ try_monitor(m);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ DebugObject_Init(&o->d_obj);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void NCDUdevClient_Free (NCDUdevClient *o)
|
|
|
|
|
+{
|
|
|
|
|
+ DebugObject_Free(&o->d_obj);
|
|
|
|
|
+ NCDUdevManager *m = o->m;
|
|
|
|
|
+
|
|
|
|
|
+ // free events
|
|
|
|
|
+ LinkedList1Node *list_node;
|
|
|
|
|
+ while (list_node = LinkedList1_GetFirst(&o->events_list)) {
|
|
|
|
|
+ struct NCDUdevClient_event *e = UPPER_OBJECT(list_node, struct NCDUdevClient_event, events_list_node);
|
|
|
|
|
+ free_event(o, e);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // free next job
|
|
|
|
|
+ BPending_Free(&o->next_job);
|
|
|
|
|
+
|
|
|
|
|
+ // remove from manager's list
|
|
|
|
|
+ LinkedList1_Remove(&m->clients_list, &o->clients_list_node);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void NCDUdevClient_Pause (NCDUdevClient *o)
|
|
|
|
|
+{
|
|
|
|
|
+ DebugObject_Access(&o->d_obj);
|
|
|
|
|
+ ASSERT(o->running)
|
|
|
|
|
+
|
|
|
|
|
+ // set not running
|
|
|
|
|
+ o->running = 0;
|
|
|
|
|
+
|
|
|
|
|
+ // unset next job to avoid reporting queued events
|
|
|
|
|
+ BPending_Unset(&o->next_job);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void NCDUdevClient_Continue (NCDUdevClient *o)
|
|
|
|
|
+{
|
|
|
|
|
+ DebugObject_Access(&o->d_obj);
|
|
|
|
|
+ ASSERT(!o->running)
|
|
|
|
|
+
|
|
|
|
|
+ // set running
|
|
|
|
|
+ o->running = 1;
|
|
|
|
|
+
|
|
|
|
|
+ // set next job if we have events queued
|
|
|
|
|
+ if (!LinkedList1_IsEmpty(&o->events_list)) {
|
|
|
|
|
+ BPending_Set(&o->next_job);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|