#include #include #include #include #include #include #include #include #include #include #include #include #include "plugin.h" #define MANDI_DAEMON_SERVICE PLUGIN_ROOT_INTF typedef struct { DBusConnection *bus; DBusWatch *bus_read_watch; int bus_read_fd; } mandi_daemon_t; extern plugin_t wpa_supplicant_plugin; extern plugin_t ifw_plugin; plugin_t *plugins[] = { &wpa_supplicant_plugin, &ifw_plugin, NULL, }; static mandi_daemon_t *mandi_daemon_p; /* global variable used in signal handlers only */ static void sigquit(int signum); static int mandi_daemon_init(mandi_daemon_t *daemon); static void mandi_daemon_exit(mandi_daemon_t *daemon, int exit_code); static void mandi_daemon_handle_dbus(mandi_daemon_t *daemon); static int mandi_daemon_acquire_service(mandi_daemon_t *daemon); static int mandi_daemon_init_watch(mandi_daemon_t *daemon); static dbus_bool_t mandi_daemon_add_watch(DBusWatch *watch, void *data); static void mandi_daemon_toggle_watch(DBusWatch *watch, void *data); static void mandi_daemon_remove_watch(DBusWatch *watch, void *data); static DBusConnection *mandi_daemon_get_system_bus(); static int mandi_daemon_init_path(mandi_daemon_t *daemon, plugin_t *plugin); static void mandi_daemon_object_path_unregister(DBusConnection *connection, void *user_data); static DBusHandlerResult mandi_daemon_object_path_handle_message(DBusConnection *connection, DBusMessage *message, void *user_data); int main(int argc, char **argv) { mandi_daemon_t mandi_daemon; /* set up signal handlers to exit nicely when needed */ mandi_daemon_p = &mandi_daemon; signal(SIGINT, sigquit); signal(SIGTERM, sigquit); signal(SIGQUIT, sigquit); mandi_daemon_init(&mandi_daemon); if (getopt(argc, argv, "d") == 'd') { daemon(0, 0); } printf("Monitoring daemon waiting for events ...\n"); while (1) { int num_fds; fd_set read_fds; plugin_t **ptr; plugin_t *plugin; FD_ZERO(&read_fds); FD_SET(mandi_daemon.bus_read_fd, &read_fds); num_fds = mandi_daemon.bus_read_fd + 1; for (ptr = plugins; *ptr; ptr++) { plugin = *ptr; if (plugin->fd >= 0) { FD_SET(plugin->fd, &read_fds); if (plugin->fd + 1 > num_fds) { num_fds = plugin->fd + 1; } } } if (select(num_fds, &read_fds, NULL, NULL, NULL) > 0) { if (FD_ISSET(mandi_daemon.bus_read_fd, &read_fds)) { mandi_daemon_handle_dbus(&mandi_daemon); } for (ptr = plugins; *ptr; ptr++) { plugin = *ptr; if (plugin->fd >= 0 && FD_ISSET(plugin->fd, &read_fds)) { plugin->handle_incoming(plugin, mandi_daemon.bus); } } } else { fprintf(stderr, "unhandled error in select(): %s\n", strerror(errno)); } } mandi_daemon_exit(&mandi_daemon, EXIT_SUCCESS); return 0; } static void sigquit(int signum) { printf("SIGINT, SIGTERM or SIGQUIT catched, trying to exit nicely\n"); mandi_daemon_exit(mandi_daemon_p, EXIT_SUCCESS); } static int mandi_daemon_init(mandi_daemon_t *daemon) { plugin_t **ptr; plugin_t *plugin; int available_plugins = 0; daemon->bus = mandi_daemon_get_system_bus(); if (!daemon->bus) { mandi_daemon_exit(daemon, EXIT_FAILURE); } if (mandi_daemon_init_watch(daemon) != 0) { fprintf(stderr, "unable to init DBus watch\n"); mandi_daemon_exit(daemon, EXIT_FAILURE); } if (mandi_daemon_acquire_service(daemon) != 0) { fprintf(stderr, "unable to init DBus service\n"); mandi_daemon_exit(daemon, EXIT_FAILURE); } for (ptr = plugins; *ptr; ptr++) { plugin = *ptr; if (plugin->init(plugin, daemon->bus) == 0) { mandi_daemon_init_path(daemon, plugin); available_plugins++; } else { fprintf(stderr, "unable to init \"%s\" plugin\n", plugin->name); } } if (available_plugins == 0) { fprintf(stderr, "unable to init any plugin, aborting\n"); mandi_daemon_exit(daemon, EXIT_FAILURE); } return 0; } static void mandi_daemon_exit(mandi_daemon_t *daemon, int exit_code) { plugin_t **ptr; plugin_t *plugin; for (ptr = plugins; *ptr; ptr++) { plugin = *ptr; plugin->deinit(plugin, daemon->bus); } if (daemon->bus) dbus_connection_unref(daemon->bus); exit(exit_code); } static void mandi_daemon_handle_dbus(mandi_daemon_t *daemon) { dbus_watch_handle(daemon->bus_read_watch, DBUS_WATCH_READABLE); dbus_connection_dispatch(daemon->bus); } int mandi_daemon_acquire_service(mandi_daemon_t *daemon) { DBusError error; dbus_error_init(&error); if (dbus_bus_request_name(daemon->bus, MANDI_DAEMON_SERVICE, 0, &error) == -1) { fprintf(stderr, "dbus_bus_acquire_service(): %s\n", error.message); fprintf(stderr, "Make sure a DBus policy allows you to acquire this service.\n"); dbus_error_free(&error); return -1; } dbus_connection_dispatch(daemon->bus); dbus_error_free(&error); return 0; } /* get fds to be watched */ static int mandi_daemon_init_watch(mandi_daemon_t *daemon) { DBusError error; dbus_error_init(&error); if (dbus_connection_set_watch_functions(daemon->bus, mandi_daemon_add_watch, mandi_daemon_toggle_watch, mandi_daemon_remove_watch, (void *) daemon, NULL) == FALSE) { fprintf(stderr, "dbus_connection_set_watch_functions(): %s\n", error.message); dbus_error_free(&error); return -1; } dbus_connection_dispatch(daemon->bus); dbus_error_free(&error); return 0; } static dbus_bool_t mandi_daemon_add_watch(DBusWatch *watch, void *data) { mandi_daemon_t *daemon = (mandi_daemon_t *) data; if (dbus_watch_get_flags(watch) & DBUS_WATCH_READABLE) { #ifdef DEBUG fprintf(stderr, "mandi_daemon_add_watch(): READABLE\n"); #endif daemon->bus_read_watch = watch; daemon->bus_read_fd = dbus_watch_get_unix_fd(daemon->bus_read_watch); } /* do nothing for WRITABLE watch, we dispatch when needed */ return TRUE; } static void mandi_daemon_toggle_watch(DBusWatch *watch, void *data) { #ifdef DEBUG fprintf(stderr, "mandi_daemon_toggle_watch()\n"); #endif /* FIXME : do we need to do something here ? */ } static void mandi_daemon_remove_watch(DBusWatch *watch, void *data) { if (dbus_watch_get_flags(watch) & DBUS_WATCH_READABLE) { #ifdef DEBUG fprintf(stderr, "mandi_daemon_remove_watch(): READABLE\n"); #endif /* FIXME : do we need to do something here ? */ } } /* set a connection to the system bus */ static DBusConnection *mandi_daemon_get_system_bus() { DBusConnection *bus; DBusError error; dbus_error_init(&error); bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error); if (!bus) { fprintf(stderr, "Failed to connect to the D-BUS daemon: %s\n", error.message); dbus_error_free(&error); return NULL; } dbus_error_free(&error); return bus; } static int mandi_daemon_init_path(mandi_daemon_t *daemon, plugin_t *plugin) { struct DBusObjectPathVTable object_path_vtable = { mandi_daemon_object_path_unregister, mandi_daemon_object_path_handle_message, NULL, NULL, NULL, NULL }; DBusError error; dbus_error_init(&error); if (dbus_connection_register_object_path(daemon->bus, plugin->path, &object_path_vtable, plugin) == FALSE) { fprintf(stderr, "dbus_connection_register_object_path(): not enough memory\n"); dbus_error_free(&error); return -1; } dbus_connection_dispatch(daemon->bus); dbus_error_free(&error); return 0; } static void mandi_daemon_object_path_unregister(DBusConnection *connection, void *user_data) { } static DBusHandlerResult mandi_daemon_object_path_handle_message(DBusConnection *connection, DBusMessage *message, void *user_data) { plugin_t *plugin = (plugin_t *) user_data; printf("handling method call '%s' on interface '%s'\n", dbus_message_get_member(message), dbus_message_get_interface(message)); return plugin->handle_message(connection, message, plugin); }