Index: dhcpcd-dbus.c |
diff --git a/dhcpcd-dbus.c b/dhcpcd-dbus.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..36390107f6bc795064e9406cacfb2db142d33b9b |
--- /dev/null |
+++ b/dhcpcd-dbus.c |
@@ -0,0 +1,626 @@ |
+/* |
+ * dhcpcd-dbus |
+ * Copyright 2009 Roy Marples <roy@marples.name> |
+ * |
+ * Redistribution and use in source and binary forms, with or without |
+ * modification, are permitted provided that the following conditions |
+ * are met: |
+ * 1. Redistributions of source code must retain the above copyright |
+ * notice, this list of conditions and the following disclaimer. |
+ * 2. Redistributions in binary form must reproduce the above copyright |
+ * notice, this list of conditions and the following disclaimer in the |
+ * documentation and/or other materials provided with the distribution. |
+ * |
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
+ * SUCH DAMAGE. |
+ */ |
+ |
+#include <errno.h> |
+#include <poll.h> |
+#include <signal.h> |
+#include <stdio.h> |
+#include <stdlib.h> |
+#include <string.h> |
+#include <syslog.h> |
+ |
+#include <dbus/dbus.h> |
+ |
+#include "config.h" |
+#include "eloop.h" |
+#include "dbus-dict.h" |
+#include "dhcpcd-dbus.h" |
+#include "dhcpcd.h" |
+ |
+#define S_EINVAL DHCPCD_SERVICE ".InvalidArgument" |
+#define S_ARGS "Not enough arguments" |
+ |
+static DBusConnection *connection; |
+ |
+static const char dhcpcd_introspection_xml[] = |
+ " <method name=\"GetVersion\">\n" |
+ " <arg name=\"version\" direction=\"out\" type=\"s\"/>\n" |
+ " </method>\n" |
+ " <method name=\"GetInterfaces\">\n" |
+ " <arg name=\"interfaces\" direction=\"out\" type=\"a{sa{sv}}\"/>\n" |
+ " </method>\n" |
+ " <method name=\"GetStatus\">\n" |
+ " <arg name=\"Status\" direction=\"out\" type=\"s\"/>\n" |
+ " </method>\n" |
+ " <method name=\"Rebind\">\n" |
+ " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" |
+ " </method>\n" |
+ " <method name=\"Release\">\n" |
+ " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" |
+ " </method>\n" |
+ " <method name=\"Stop\">\n" |
+ " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" |
+ " </method>\n" |
+ " <signal name=\"Event\">\n" |
+ " <arg name=\"configuration\" type=\"usa{sv}\"/>\n" |
+ " </signal>\n" |
+ " <signal name=\"StatusChanged\">\n" |
+ " <arg name=\"status\" type=\"us\"/>\n" |
+ " </signal>\n"; |
+ |
+static const struct o_dbus const dhos[] = { |
+ { "ip_address=", DBUS_TYPE_UINT32, 0, "IPAddress" }, |
+ { "server_name=", DBUS_TYPE_STRING, 0, "ServerName"}, |
+ { "subnet_mask=", DBUS_TYPE_UINT32, 0, "SubnetMask" }, |
+ { "subnet_cidr=", DBUS_TYPE_BYTE, 0, "SubnetCIDR" }, |
+ { "network_number=", DBUS_TYPE_UINT32, 0, "NetworkNumber" }, |
+ { "classless_static_routes=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "ClasslessStaticRoutes" }, |
+ { "ms_classless_static_routes=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "MSClasslessStaticRoutes" }, |
+ { "static_routes=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "StaticRoutes"} , |
+ { "routers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "Routers" }, |
+ { "time_offset=", DBUS_TYPE_UINT32, 0, "TimeOffset" }, |
+ { "time_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "TimeServers" }, |
+ { "ien116_name_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "IEN116NameServers" }, |
+ { "domain_name_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "DomainNameServers" }, |
+ { "log_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "LogServers" }, |
+ { "cookie_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "CookieServers" }, |
+ { "lpr_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "LPRServers" }, |
+ { "impress_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "ImpressServers" }, |
+ { "resource_location_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "ResourceLocationServers" }, |
+ { "host_name=", DBUS_TYPE_STRING, 0, "Hostname" }, |
+ { "boot_size=", DBUS_TYPE_UINT16, 0, "BootSize" }, |
+ { "merit_dump=", DBUS_TYPE_STRING, 0, "MeritDump" }, |
+ { "domain_name=", DBUS_TYPE_STRING, 0, "DomainName" }, |
+ { "swap_server=", DBUS_TYPE_UINT32, 0, "SwapServer" }, |
+ { "root_path=", DBUS_TYPE_STRING, 0, "RootPath" }, |
+ { "extensions_path=", DBUS_TYPE_STRING, 0, "ExtensionsPath" }, |
+ { "ip_forwarding=", DBUS_TYPE_BOOLEAN, 0, "IPForwarding" }, |
+ { "non_local_source_routing=", DBUS_TYPE_BOOLEAN, 0, |
+ "NonLocalSourceRouting" }, |
+ { "policy_filter=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "PolicyFilter" }, |
+ { "max_dgram_reassembly=", DBUS_TYPE_INT16, 0, |
+ "MaxDatagramReassembly" }, |
+ { "default_ip_ttl=", DBUS_TYPE_UINT16, 0, "DefaultIPTTL" }, |
+ { "path_mtu_aging_timeout=", DBUS_TYPE_UINT32, 0, |
+ "PathMTUAgingTimeout" }, |
+ { "path_mtu_plateau_table=" ,DBUS_TYPE_ARRAY, DBUS_TYPE_UINT16, |
+ "PolicyFilter"} , |
+ { "interface_mtu=", DBUS_TYPE_UINT16, 0, "InterfaceMTU" }, |
+ { "all_subnets_local=", DBUS_TYPE_BOOLEAN, 0, "AllSubnetsLocal" }, |
+ { "broadcast_address=", DBUS_TYPE_UINT32, 0, "BroadcastAddress" }, |
+ { "perform_mask_discovery=", DBUS_TYPE_BOOLEAN, 0, |
+ "PerformMaskDiscovery" }, |
+ { "mask_supplier=", DBUS_TYPE_BOOLEAN, 0, "MaskSupplier" }, |
+ { "router_discovery=", DBUS_TYPE_BOOLEAN, 0, "RouterDiscovery" }, |
+ { "router_solicitiation_address=", DBUS_TYPE_UINT32, 0, |
+ "RouterSolicationAddress" }, |
+ { "trailer_encapsulation=", DBUS_TYPE_BOOLEAN, 0, |
+ "TrailerEncapsulation" }, |
+ { "arp_cache_timeout=", DBUS_TYPE_UINT32, 0, "ARPCacheTimeout" }, |
+ { "ieee802_3_encapsulation=", DBUS_TYPE_UINT16, 0, |
+ "IEEE8023Encapsulation" }, |
+ { "default_tcp_ttl=", DBUS_TYPE_BYTE, 0, "DefaultTCPTTL" }, |
+ { "tcp_keepalive_interval=", DBUS_TYPE_UINT32, 0, |
+ "TCPKeepAliveInterval" }, |
+ { "tcp_keepalive_garbage=", DBUS_TYPE_BOOLEAN, 0, |
+ "TCPKeepAliveGarbage" }, |
+ { "nis_domain=", DBUS_TYPE_STRING, 0, "NISDomain" }, |
+ { "nis_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "NISServers" }, |
+ { "ntp_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "NTPServers" }, |
+ { "vendor_encapsulated_optons=", DBUS_TYPE_STRING, 0, |
+ "VendorEncapsulatedOptions" }, |
+ { "netbios_name_servers=" ,DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "NetBIOSNameServers" }, |
+ { "netbios_dd_server=", DBUS_TYPE_UINT32, 0, "NetBIOSDDServer" }, |
+ { "netbios_node_type=", DBUS_TYPE_BYTE, 0, "NetBIOSNodeType" }, |
+ { "netbios_scope=", DBUS_TYPE_STRING, 0, "NetBIOSScope" }, |
+ { "font_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "FontServers" }, |
+ { "x_display_manager=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "XDisplayManager" }, |
+ { "dhcp_requested_address=", DBUS_TYPE_UINT32, 0, |
+ "DHCPRequestedAddress" }, |
+ { "dhcp_lease_time=", DBUS_TYPE_UINT32, 0, "DHCPLeaseTime" }, |
+ { "dhcp_option_overload=", DBUS_TYPE_BOOLEAN, 0, |
+ "DHCPOptionOverload" }, |
+ { "dhcp_message_type=", DBUS_TYPE_BYTE, 0, "DHCPMessageType" }, |
+ { "dhcp_server_identifier=", DBUS_TYPE_UINT32, 0, |
+ "DHCPServerIdentifier" }, |
+ { "dhcp_message=", DBUS_TYPE_STRING, 0, "DHCPMessage" }, |
+ { "dhcp_max_message_size=", DBUS_TYPE_UINT16, 0, |
+ "DHCPMaxMessageSize" }, |
+ { "dhcp_renewal_time=", DBUS_TYPE_UINT32, 0, "DHCPRenewalTime" }, |
+ { "dhcp_rebinding_time=", DBUS_TYPE_UINT32, 0, "DHCPRebindingTime" }, |
+ { "nisplus_domain=", DBUS_TYPE_STRING, 0, "NISPlusDomain" }, |
+ { "nisplus_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "NISPlusServers" }, |
+ { "tftp_server_name=", DBUS_TYPE_STRING, 0, "TFTPServerName" }, |
+ { "bootfile_name=", DBUS_TYPE_STRING, 0, "BootFileName" }, |
+ { "mobile_ip_home_agent=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "MobileIPHomeAgent" }, |
+ { "smtp_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "SMTPServer" }, |
+ { "pop_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "POPServer" }, |
+ { "nntp_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "NNTPServer" }, |
+ { "www_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "WWWServer" }, |
+ { "finger_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "FingerServer" }, |
+ { "irc_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "IRCServer" }, |
+ { "streettalk_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "StreetTalkServer" }, |
+ { "streettalk_directory_assistance_server=", DBUS_TYPE_ARRAY, |
+ DBUS_TYPE_UINT32, "StreetTalkDirectoryAssistanceServer" }, |
+ { "user_class=", DBUS_TYPE_STRING, 0, "UserClass" }, |
+ { "new_fqdn_name=", DBUS_TYPE_STRING, 0, "FQDNName" }, |
+ { "nds_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "NDSServers" }, |
+ { "nds_tree_name=", DBUS_TYPE_STRING, 0, "NDSTreeName" }, |
+ { "nds_context=", DBUS_TYPE_STRING, 0, "NDSContext" }, |
+ { "bcms_controller_names=", DBUS_TYPE_STRING, 0, |
+ "BCMSControllerNames" }, |
+ { "client_last_transaction_time=", DBUS_TYPE_UINT32, 0, |
+ "ClientLastTransactionTime" }, |
+ { "associated_ip=", DBUS_TYPE_UINT32, 0, "AssociatedIP" }, |
+ { "uap_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "UAPServers" }, |
+ { "netinfo_server_address=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, |
+ "NetinfoServerAddress" }, |
+ { "netinfo_server_tag=", DBUS_TYPE_STRING, 0, "NetinfoServerTag" }, |
+ { "default_url=", DBUS_TYPE_STRING, 0, "DefaultURL" }, |
+ { "subnet_selection=", DBUS_TYPE_UINT32, 0, "SubnetSelection" }, |
+ { "domain_search=", DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, |
+ "DomainSearch" }, |
+ { NULL, 0, 0, NULL } |
+}; |
+ |
+static int |
+append_config(DBusMessageIter *iter, |
+ const char *prefix, char **env, ssize_t elen) |
+{ |
+ char **eenv, *p; |
+ const struct o_dbus *dhop; |
+ size_t l, lp; |
+ int retval; |
+ |
+ retval = 0; |
+ lp = strlen(prefix); |
+ for (eenv = env + elen; env < eenv; env++) { |
+ p = env[0]; |
+ for (dhop = dhos; dhop->var; dhop++) { |
+ l = strlen(dhop->var); |
+ if (strncmp(p, dhop->var, l) == 0) { |
+ retval = dict_append_config_item(iter, |
+ dhop, p + l); |
+ break; |
+ } |
+ if (strncmp(p, prefix, lp) == 0 && |
+ strncmp(p + lp, dhop->var, l) == 0) |
+ { |
+ retval = dict_append_config_item(iter, |
+ dhop, p + l + lp); |
+ break; |
+ } |
+ } |
+ if (retval == -1) |
+ break; |
+ } |
+ return retval; |
+} |
+ |
+DBusHandlerResult _printf(4, 5) |
+ return_dbus_error(DBusConnection *con, DBusMessage *msg, |
+ const char *name, const char *fmt, ...) |
+{ |
+ char buffer[1024]; |
+ DBusMessage *reply; |
+ va_list args; |
+ |
+ va_start(args, fmt); |
+ vsnprintf(buffer, sizeof(buffer), fmt, args); |
+ va_end(args); |
+ reply = dbus_message_new_error(msg, name, buffer); |
+ dbus_connection_send(con, reply, NULL); |
+ dbus_message_unref(reply); |
+ return DBUS_HANDLER_RESULT_HANDLED; |
+} |
+ |
+const char *dhcpcd_status = NULL; /* XXX */ |
+ |
+static DBusHandlerResult |
+return_status(DBusConnection *con, DBusMessage *msg) |
+{ |
+ DBusMessage *reply; |
+ |
+ reply = dbus_message_new_method_return(msg); |
+ dbus_message_append_args(reply, |
+ DBUS_TYPE_STRING, &dhcpcd_status, |
+ DBUS_TYPE_INVALID); |
+ dbus_connection_send(con, reply, NULL); |
+ dbus_message_unref(reply); |
+ return DBUS_HANDLER_RESULT_HANDLED; |
+} |
+ |
+void |
+dhcpcd_dbus_signal_status(const char *status) |
+{ |
+ DBusMessage *msg; |
+ DBusMessageIter args; |
+ int pid = getpid(); |
+ |
+ syslog(LOG_INFO, "status changed to %s", status); |
+ |
+ msg = dbus_message_new_signal(DHCPCD_PATH, DHCPCD_SERVICE, |
+ "StatusChanged"); |
+ if (msg == NULL) { |
+ syslog(LOG_ERR, "failed to make a status changed message"); |
+ return; |
+ } |
+ dbus_message_iter_init_append(msg, &args); |
+ dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid); |
+ dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &status); |
+ if (!dbus_connection_send(connection, msg, NULL)) |
+ syslog(LOG_ERR, "failed to send status to dbus"); |
+ dbus_message_unref(msg); |
+} |
+ |
+void |
+dhcpcd_dbus_configure(const struct interface *ifp, const char *reason) |
+{ |
+ const struct if_options *ifo = ifp->state->options; |
+ DBusMessage* msg; |
+ DBusMessageIter args, dict; |
+ int pid = getpid(); |
+ char **env; |
+ ssize_t e, elen; |
+ int retval; |
+ |
+ syslog(LOG_INFO, "event %s on interface %s", reason, ifp->name); |
+ |
+ msg = dbus_message_new_signal(DHCPCD_PATH, DHCPCD_SERVICE, "Event"); |
+ if (msg == NULL) { |
+ syslog(LOG_ERR, "failed to make a configure message"); |
+ return; |
+ } |
+ dbus_message_iter_init_append(msg, &args); |
+ dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid); |
+ dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &reason); |
+ dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, |
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
+ DBUS_TYPE_STRING_AS_STRING |
+ DBUS_TYPE_VARIANT_AS_STRING |
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, |
+ &dict); |
+ if (ifp->state->new != NULL) { |
+ e = configure_env(NULL, NULL, ifp->state->new, ifo); |
+ if (e > 0) { |
+ env = xzalloc(sizeof(char *) * (e + 1)); |
+ elen = configure_env(env, "new", ifp->state->new, ifo); |
+ } |
+ retval = append_config(&dict, "new_", env, elen); |
+ } else if (ifp->state->old != NULL) { |
+ e = configure_env(NULL, NULL, ifp->state->old, ifo); |
+ if (e > 0) { |
+ env = xzalloc(sizeof(char *) * (elen + e + 1)); |
+ elen = configure_env(env, "old", ifp->state->old, ifo); |
+ } |
+ retval = append_config(&dict, "old_", env, elen); |
+ } else |
+ retval = 0; |
+ /* XXX reclaim env */ |
+ dbus_message_iter_close_container(&args, &dict); |
+ if (retval == 0) { |
+ if (!dbus_connection_send(connection, msg, NULL)) |
+ syslog(LOG_ERR, "failed to send dhcp to dbus"); |
+ } else |
+ syslog(LOG_ERR, "failed to construct dbus message"); |
+ dbus_message_unref(msg); |
+} |
+ |
+static const char introspection_header_xml[] = |
+ "<!DOCTYPE node PUBLIC \"-//freedesktop//" |
+ "DTD D-BUS Object Introspection 1.0//EN\"\n" |
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" |
+ "<node name=\"" DHCPCD_PATH "\">\n" |
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" |
+ " <method name=\"Introspect\">\n" |
+ " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n" |
+ " </method>\n" |
+ " </interface>\n" |
+ " <interface name=\"" DHCPCD_SERVICE "\">\n"; |
+ |
+static const char introspection_footer_xml[] = |
+ " </interface>\n" |
+ "</node>\n"; |
+ |
+static DBusHandlerResult |
+introspect(DBusConnection *con, DBusMessage *msg) |
+{ |
+ DBusMessage *reply; |
+ char *xml; |
+ size_t len; |
+ |
+ len = sizeof(introspection_header_xml) - 1 |
+ + sizeof(dhcpcd_introspection_xml) - 1 |
+ + sizeof(introspection_footer_xml) - 1 |
+ + 1; /* terminal \0 */ |
+ xml = malloc(len); |
+ if (xml == NULL) |
+ return DBUS_HANDLER_RESULT_HANDLED; |
+ snprintf(xml, len, "%s%s%s", |
+ introspection_header_xml, |
+ dhcpcd_introspection_xml, |
+ introspection_footer_xml); |
+ reply = dbus_message_new_method_return(msg); |
+ dbus_message_append_args(reply, |
+ DBUS_TYPE_STRING, &xml, |
+ DBUS_TYPE_INVALID); |
+ dbus_connection_send(con, reply, NULL); |
+ dbus_message_unref(reply); |
+ free(xml); |
+ return DBUS_HANDLER_RESULT_HANDLED; |
+} |
+ |
+static DBusHandlerResult |
+version(DBusConnection *con, DBusMessage *msg, const char *ver) |
+{ |
+ DBusMessage *reply; |
+ |
+ reply = dbus_message_new_method_return(msg); |
+ dbus_message_append_args(reply, |
+ DBUS_TYPE_STRING, &ver, |
+ DBUS_TYPE_INVALID); |
+ dbus_connection_send(con, reply, NULL); |
+ dbus_message_unref(reply); |
+ return DBUS_HANDLER_RESULT_HANDLED; |
+} |
+ |
+static DBusHandlerResult |
+dhcpcd_get_interfaces(DBusConnection *con, DBusMessage *msg) |
+{ |
+ DBusMessage *reply; |
+ DBusMessageIter _ifaces, _iface, entry, dict; |
+ struct interface *ifp; |
+ char **env; |
+ ssize_t e, elen; |
+ int retval; |
+ |
+ reply = dbus_message_new_method_return(msg); |
+ dbus_message_iter_init_append(reply, &_ifaces); |
+ |
+ dbus_message_iter_open_container(&_ifaces, DBUS_TYPE_ARRAY, |
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
+ DBUS_TYPE_STRING_AS_STRING |
+ DBUS_TYPE_ARRAY_AS_STRING |
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
+ DBUS_TYPE_STRING_AS_STRING |
+ DBUS_TYPE_VARIANT_AS_STRING |
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING |
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, |
+ &_iface); |
+ |
+ for (ifp = ifaces; ifp != NULL; ifp = ifp->next) { |
+ const struct if_options *ifo = ifp->state->options; |
+ |
+ dbus_message_iter_open_container(&_iface, |
+ DBUS_TYPE_DICT_ENTRY, NULL, &entry); |
+ dbus_message_iter_append_basic(&entry, |
+ DBUS_TYPE_STRING, &ifp->name); |
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_ARRAY, |
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
+ DBUS_TYPE_STRING_AS_STRING |
+ DBUS_TYPE_VARIANT_AS_STRING |
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, |
+ &dict); |
+ e = configure_env(NULL, NULL, ifp->state->new, ifo); |
+ if (e > 0) { |
+ env = xzalloc(sizeof(char *) * (e + 1)); |
+ elen = configure_env(env, "new", ifp->state->new, ifo); |
+ } |
+ retval = append_config(&dict, "new_", env, elen); |
+ /* XXX reclaim env */ |
+ dbus_message_iter_close_container(&entry, &dict); |
+ dbus_message_iter_close_container(&_iface, &entry); |
+ } |
+ |
+ dbus_message_iter_close_container(&_ifaces, &_iface); |
+ dbus_connection_send(con, reply, NULL); |
+ dbus_message_unref(reply); |
+ return DBUS_HANDLER_RESULT_HANDLED; |
+} |
+ |
+static DBusHandlerResult |
+dbus_ack(DBusConnection *con, DBusMessage *msg) |
+{ |
+ DBusMessage *reply; |
+ |
+ reply = dbus_message_new_method_return(msg); |
+ dbus_connection_send(con, reply, NULL); |
+ dbus_message_unref(reply); |
+ return DBUS_HANDLER_RESULT_HANDLED; |
+} |
+ |
+static DBusHandlerResult |
+msg_handler(DBusConnection *con, DBusMessage *msg, _unused void *data) |
+{ |
+#define IsMethod(msg, method) \ |
+ dbus_message_is_method_call(msg, DHCPCD_SERVICE, method) |
+ if (IsMethod(msg, "Introspect")) { |
+ return introspect(con, msg); |
+ } else if (IsMethod(msg, "GetVersion")) { |
+ return version(con, msg, VERSION); |
+ } else if (IsMethod(msg, "GetInterfaces")) { |
+ return dhcpcd_get_interfaces(con, msg); |
+ } else if (IsMethod(msg, "GetStatus")) { |
+ return return_status(con, msg); |
+ } else if (IsMethod(msg, "Rebind")) { |
+ bind_interface(ifaces); /* XXX */ |
+ return dbus_ack(con, msg); |
+ } else if (IsMethod(msg, "Release")) { |
+ handle_signal(SIGHUP); |
+ return dbus_ack(con, msg); |
+ } else if (IsMethod(msg, "Stop")) { |
+ /* NB: must ack first 'cuz handle_signal exit's */ |
+ (void) dbus_ack(con, msg); |
+ handle_signal(SIGINT); |
+ /*NOTREACHED*/ |
+ } |
+ return return_dbus_error(con, msg, S_EINVAL, S_ARGS); |
+#undef IsMethod |
+} |
+ |
+static void |
+dbus_event(int revents, void *watch) |
+{ |
+ int flags; |
+ |
+ flags = 0; |
+ if (revents & POLLIN) |
+ flags |= DBUS_WATCH_READABLE; |
+ if (revents & POLLOUT) |
+ flags |= DBUS_WATCH_WRITABLE; |
+ if (revents & POLLHUP) |
+ flags |= DBUS_WATCH_HANGUP; |
+ if (revents & POLLERR) |
+ flags |= DBUS_WATCH_ERROR; |
+ if (flags != 0) |
+ dbus_watch_handle((DBusWatch *)watch, flags); |
+ |
+ if (connection != NULL) { |
+ dbus_connection_ref(connection); |
+ while (dbus_connection_dispatch(connection) == |
+ DBUS_DISPATCH_DATA_REMAINS) |
+ ; |
+ dbus_connection_unref(connection); |
+ } |
+} |
+ |
+static dbus_bool_t |
+add_watch(DBusWatch *watch, _unused void *data) |
+{ |
+ int fd, flags, eflags; |
+ |
+ fd = dbus_watch_get_unix_fd(watch); |
+ flags = dbus_watch_get_flags(watch); |
+ eflags = POLLHUP | POLLERR; |
+ if (flags & DBUS_WATCH_READABLE) |
+ eflags |= POLLIN; |
+ if (flags & DBUS_WATCH_WRITABLE) |
+ eflags |= POLLOUT; |
+ if (add_event_flags(fd, eflags, dbus_event, watch) == 0) |
+ return TRUE; |
+ return FALSE; |
+} |
+ |
+static void |
+remove_watch(DBusWatch *watch, _unused void *data) |
+{ |
+ int fd; |
+ |
+ fd = dbus_watch_get_unix_fd(watch); |
+ delete_event(fd); |
+} |
+ |
+void |
+dhcpcd_dbus_close(void) |
+{ |
+ if (connection) { |
+ dbus_connection_unref(connection); |
+ connection = NULL; |
+ } |
+} |
+ |
+int |
+dhcpcd_dbus_init(void) |
+{ |
+ DBusObjectPathVTable vt = { |
+ NULL, &msg_handler, NULL, NULL, NULL, NULL |
+ }; |
+ DBusError err; |
+ int ret; |
+ |
+ dbus_error_init(&err); |
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, &err); |
+ if (connection == NULL) { |
+ if (dbus_error_is_set(&err)) |
+ syslog(LOG_ERR, "%s", err.message); |
+ else |
+ syslog(LOG_ERR, "failed to get a dbus connection"); |
+ return -1; |
+ } |
+ atexit(dhcpcd_dbus_close); |
+ |
+#if 0 |
+ ret = dbus_bus_request_name(connection, DHCPCD_SERVICE, |
+ DBUS_NAME_FLAG_REPLACE_EXISTING, &err); |
+ if (dbus_error_is_set(&err)) { |
+ syslog(LOG_ERR, "%s", err.message); |
+ return -1; |
+ } |
+#endif |
+ if (!dbus_connection_set_watch_functions(connection, |
+ add_watch, remove_watch, NULL, NULL, NULL)) |
+ { |
+ syslog(LOG_ERR, "dbus: failed to set watch functions"); |
+ return -1; |
+ } |
+ if (!dbus_connection_register_object_path(connection, |
+ DHCPCD_PATH, &vt, NULL)) |
+ { |
+ syslog(LOG_ERR, "dbus: failed to register object path"); |
+ return -1; |
+ } |
+ return 0; |
+} |
+ |
+int |
+configure(struct interface *ifp) |
+{ |
+ if (ifp->state->new != NULL) { |
+ /* push state over d-bus */ |
+ dhcpcd_dbus_configure(ifp, ifp->state->reason); |
+ |
+ if (write_lease(ifp, ifp->state->new) == -1) |
+ syslog(LOG_ERR, "write_lease: %m"); |
+ } |
+ return 0; |
+} |
+ |
+int |
+run_script(const struct interface *ifp) |
+{ |
+ syslog(LOG_DEBUG, "executing `%s', reason %s", |
+ ifp->name, ifp->state->reason); |
+#if 0 |
+ /* push state over d-bus */ |
+ dhcpcd_dbus_configure(ifp, ifp->state->reason); |
+#endif |
+ return 0; |
+} |