3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2012 Intel Corporation. All rights reserved.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include <sys/signalfd.h>
37 #include <readline/readline.h>
38 #include <readline/history.h>
41 #include "gdbus/gdbus.h"
42 #include "monitor/uuid.h"
47 /* String display constants */
48 #define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
49 #define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
50 #define COLORED_DEL COLOR_RED "DEL" COLOR_OFF
52 #define PROMPT_ON COLOR_BLUE "[bluetooth]" COLOR_OFF "# "
53 #define PROMPT_OFF "[bluetooth]# "
55 static GMainLoop *main_loop;
56 static DBusConnection *dbus_conn;
58 static GDBusProxy *agent_manager;
59 static char *auto_register_agent = NULL;
61 static GDBusProxy *default_ctrl;
62 static GDBusProxy *default_dev;
63 static GDBusProxy *default_attr;
64 static GList *ctrl_list;
65 static GList *dev_list;
67 static guint input = 0;
69 static const char * const agent_arguments[] = {
80 static void proxy_leak(gpointer data)
82 printf("Leaking proxy %p\n", data);
85 static void connect_handler(DBusConnection *connection, void *user_data)
87 rl_set_prompt(PROMPT_ON);
93 static void disconnect_handler(DBusConnection *connection, void *user_data)
95 rl_set_prompt(PROMPT_OFF);
100 g_list_free(ctrl_list);
105 g_list_free(dev_list);
109 static void print_adapter(GDBusProxy *proxy, const char *description)
111 DBusMessageIter iter;
112 const char *address, *name;
114 if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
117 dbus_message_iter_get_basic(&iter, &address);
119 if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
120 dbus_message_iter_get_basic(&iter, &name);
124 rl_printf("%s%s%sController %s %s %s\n",
125 description ? "[" : "",
127 description ? "] " : "",
129 default_ctrl == proxy ? "[default]" : "");
133 static void print_device(GDBusProxy *proxy, const char *description)
135 DBusMessageIter iter;
136 const char *address, *name;
138 if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
141 dbus_message_iter_get_basic(&iter, &address);
143 if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
144 dbus_message_iter_get_basic(&iter, &name);
148 rl_printf("%s%s%sDevice %s %s\n",
149 description ? "[" : "",
151 description ? "] " : "",
155 static void print_iter(const char *label, const char *name,
156 DBusMessageIter *iter)
159 dbus_uint32_t valu32;
160 dbus_uint16_t valu16;
164 DBusMessageIter subiter;
168 rl_printf("%s%s is nil\n", label, name);
172 switch (dbus_message_iter_get_arg_type(iter)) {
173 case DBUS_TYPE_INVALID:
174 rl_printf("%s%s is invalid\n", label, name);
176 case DBUS_TYPE_STRING:
177 case DBUS_TYPE_OBJECT_PATH:
178 dbus_message_iter_get_basic(iter, &valstr);
179 rl_printf("%s%s: %s\n", label, name, valstr);
181 case DBUS_TYPE_BOOLEAN:
182 dbus_message_iter_get_basic(iter, &valbool);
183 rl_printf("%s%s: %s\n", label, name,
184 valbool == TRUE ? "yes" : "no");
186 case DBUS_TYPE_UINT32:
187 dbus_message_iter_get_basic(iter, &valu32);
188 rl_printf("%s%s: 0x%06x\n", label, name, valu32);
190 case DBUS_TYPE_UINT16:
191 dbus_message_iter_get_basic(iter, &valu16);
192 rl_printf("%s%s: 0x%04x\n", label, name, valu16);
194 case DBUS_TYPE_INT16:
195 dbus_message_iter_get_basic(iter, &vals16);
196 rl_printf("%s%s: %d\n", label, name, vals16);
199 dbus_message_iter_get_basic(iter, &byte);
200 rl_printf("%s%s: 0x%02x\n", label, name, byte);
202 case DBUS_TYPE_VARIANT:
203 dbus_message_iter_recurse(iter, &subiter);
204 print_iter(label, name, &subiter);
206 case DBUS_TYPE_ARRAY:
207 dbus_message_iter_recurse(iter, &subiter);
208 while (dbus_message_iter_get_arg_type(&subiter) !=
210 print_iter(label, name, &subiter);
211 dbus_message_iter_next(&subiter);
214 case DBUS_TYPE_DICT_ENTRY:
215 dbus_message_iter_recurse(iter, &subiter);
216 entry = g_strconcat(name, " Key", NULL);
217 print_iter(label, entry, &subiter);
220 entry = g_strconcat(name, " Value", NULL);
221 dbus_message_iter_next(&subiter);
222 print_iter(label, entry, &subiter);
226 rl_printf("%s%s has unsupported type\n", label, name);
231 static void print_property(GDBusProxy *proxy, const char *name)
233 DBusMessageIter iter;
235 if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
238 print_iter("\t", name, &iter);
241 static void print_uuids(GDBusProxy *proxy)
243 DBusMessageIter iter, value;
245 if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
248 dbus_message_iter_recurse(&iter, &value);
250 while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
251 const char *uuid, *text;
253 dbus_message_iter_get_basic(&value, &uuid);
255 text = uuidstr_to_str(uuid);
260 str[sizeof(str) - 1] = '\0';
262 n = snprintf(str, sizeof(str), "%s", text);
263 if (n > sizeof(str) - 1) {
264 str[sizeof(str) - 2] = '.';
265 str[sizeof(str) - 3] = '.';
266 if (str[sizeof(str) - 4] == ' ')
267 str[sizeof(str) - 4] = '.';
272 rl_printf("\tUUID: %s%*c(%s)\n",
273 str, 26 - n, ' ', uuid);
275 rl_printf("\tUUID: %*c(%s)\n", 26, ' ', uuid);
277 dbus_message_iter_next(&value);
281 static gboolean device_is_child(GDBusProxy *device, GDBusProxy *master)
283 DBusMessageIter iter;
284 const char *adapter, *path;
289 if (g_dbus_proxy_get_property(device, "Adapter", &iter) == FALSE)
292 dbus_message_iter_get_basic(&iter, &adapter);
293 path = g_dbus_proxy_get_path(master);
295 if (!strcmp(path, adapter))
301 static gboolean service_is_child(GDBusProxy *service)
304 DBusMessageIter iter;
305 const char *device, *path;
307 if (g_dbus_proxy_get_property(service, "Device", &iter) == FALSE)
310 dbus_message_iter_get_basic(&iter, &device);
312 for (l = dev_list; l; l = g_list_next(l)) {
313 GDBusProxy *proxy = l->data;
315 path = g_dbus_proxy_get_path(proxy);
317 if (!strcmp(path, device))
324 static void proxy_added(GDBusProxy *proxy, void *user_data)
326 const char *interface;
328 interface = g_dbus_proxy_get_interface(proxy);
330 if (!strcmp(interface, "org.bluez.Device1")) {
331 if (device_is_child(proxy, default_ctrl) == TRUE) {
332 dev_list = g_list_append(dev_list, proxy);
334 print_device(proxy, COLORED_NEW);
336 } else if (!strcmp(interface, "org.bluez.Adapter1")) {
337 ctrl_list = g_list_append(ctrl_list, proxy);
340 default_ctrl = proxy;
342 print_adapter(proxy, COLORED_NEW);
343 } else if (!strcmp(interface, "org.bluez.AgentManager1")) {
344 if (!agent_manager) {
345 agent_manager = proxy;
347 if (auto_register_agent)
348 agent_register(dbus_conn, agent_manager,
349 auto_register_agent);
351 } else if (!strcmp(interface, "org.bluez.GattService1")) {
352 if (service_is_child(proxy))
353 gatt_add_service(proxy);
354 } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
355 gatt_add_characteristic(proxy);
356 } else if (!strcmp(interface, "org.bluez.GattDescriptor1")) {
357 gatt_add_descriptor(proxy);
358 } else if (!strcmp(interface, "org.bluez.GattManager1")) {
359 gatt_add_manager(proxy);
363 static void set_default_device(GDBusProxy *proxy, const char *attribute)
366 DBusMessageIter iter;
376 if (!g_dbus_proxy_get_property(proxy, "Alias", &iter)) {
377 if (!g_dbus_proxy_get_property(proxy, "Address", &iter))
381 path = g_dbus_proxy_get_path(proxy);
383 dbus_message_iter_get_basic(&iter, &desc);
384 desc = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", desc,
385 attribute ? ":" : "",
386 attribute ? attribute + strlen(path) : "");
389 rl_set_prompt(desc ? desc : PROMPT_ON);
396 static void set_default_attribute(GDBusProxy *proxy)
400 default_attr = proxy;
402 path = g_dbus_proxy_get_path(proxy);
404 set_default_device(default_dev, path);
407 static void proxy_removed(GDBusProxy *proxy, void *user_data)
409 const char *interface;
411 interface = g_dbus_proxy_get_interface(proxy);
413 if (!strcmp(interface, "org.bluez.Device1")) {
414 if (device_is_child(proxy, default_ctrl) == TRUE) {
415 dev_list = g_list_remove(dev_list, proxy);
417 print_device(proxy, COLORED_DEL);
419 if (default_dev == proxy)
420 set_default_device(NULL, NULL);
422 } else if (!strcmp(interface, "org.bluez.Adapter1")) {
423 ctrl_list = g_list_remove(ctrl_list, proxy);
425 print_adapter(proxy, COLORED_DEL);
427 if (default_ctrl == proxy) {
429 set_default_device(NULL, NULL);
431 g_list_free(dev_list);
434 } else if (!strcmp(interface, "org.bluez.AgentManager1")) {
435 if (agent_manager == proxy) {
436 agent_manager = NULL;
437 if (auto_register_agent)
438 agent_unregister(dbus_conn, NULL);
440 } else if (!strcmp(interface, "org.bluez.GattService1")) {
441 gatt_remove_service(proxy);
443 if (default_attr == proxy)
444 set_default_attribute(NULL);
445 } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
446 gatt_remove_characteristic(proxy);
448 if (default_attr == proxy)
449 set_default_attribute(NULL);
450 } else if (!strcmp(interface, "org.bluez.GattDescriptor1")) {
451 gatt_remove_descriptor(proxy);
453 if (default_attr == proxy)
454 set_default_attribute(NULL);
455 } else if (!strcmp(interface, "org.bluez.GattManager1")) {
456 gatt_remove_manager(proxy);
460 static void property_changed(GDBusProxy *proxy, const char *name,
461 DBusMessageIter *iter, void *user_data)
463 const char *interface;
465 interface = g_dbus_proxy_get_interface(proxy);
467 if (!strcmp(interface, "org.bluez.Device1")) {
468 if (device_is_child(proxy, default_ctrl) == TRUE) {
469 DBusMessageIter addr_iter;
472 if (g_dbus_proxy_get_property(proxy, "Address",
473 &addr_iter) == TRUE) {
476 dbus_message_iter_get_basic(&addr_iter,
478 str = g_strdup_printf("[" COLORED_CHG
479 "] Device %s ", address);
483 if (strcmp(name, "Connected") == 0) {
484 dbus_bool_t connected;
486 dbus_message_iter_get_basic(iter, &connected);
488 if (connected && default_dev == NULL)
489 set_default_device(proxy, NULL);
490 else if (!connected && default_dev == proxy)
491 set_default_device(NULL, NULL);
494 print_iter(str, name, iter);
497 } else if (!strcmp(interface, "org.bluez.Adapter1")) {
498 DBusMessageIter addr_iter;
501 if (g_dbus_proxy_get_property(proxy, "Address",
502 &addr_iter) == TRUE) {
505 dbus_message_iter_get_basic(&addr_iter, &address);
506 str = g_strdup_printf("[" COLORED_CHG
507 "] Controller %s ", address);
511 print_iter(str, name, iter);
513 } else if (proxy == default_attr) {
516 str = g_strdup_printf("[" COLORED_CHG "] Attribute %s ",
517 g_dbus_proxy_get_path(proxy));
519 print_iter(str, name, iter);
524 static void message_handler(DBusConnection *connection,
525 DBusMessage *message, void *user_data)
527 rl_printf("[SIGNAL] %s.%s\n", dbus_message_get_interface(message),
528 dbus_message_get_member(message));
531 static GDBusProxy *find_proxy_by_address(GList *source, const char *address)
535 for (list = g_list_first(source); list; list = g_list_next(list)) {
536 GDBusProxy *proxy = list->data;
537 DBusMessageIter iter;
540 if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
543 dbus_message_iter_get_basic(&iter, &str);
545 if (!strcmp(str, address))
552 static gboolean check_default_ctrl(void)
555 rl_printf("No default controller available\n");
562 static gboolean parse_argument_on_off(const char *arg, dbus_bool_t *value)
564 if (!arg || !strlen(arg)) {
565 rl_printf("Missing on/off argument\n");
569 if (!strcmp(arg, "on") || !strcmp(arg, "yes")) {
574 if (!strcmp(arg, "off") || !strcmp(arg, "no")) {
579 rl_printf("Invalid argument %s\n", arg);
583 static gboolean parse_argument_agent(const char *arg, dbus_bool_t *value,
584 const char **capability)
586 const char * const *opt;
588 if (arg == NULL || strlen(arg) == 0) {
589 rl_printf("Missing on/off/capability argument\n");
593 if (strcmp(arg, "on") == 0 || strcmp(arg, "yes") == 0) {
599 if (strcmp(arg, "off") == 0 || strcmp(arg, "no") == 0) {
604 for (opt = agent_arguments; *opt; opt++) {
605 if (strcmp(arg, *opt) == 0) {
612 rl_printf("Invalid argument %s\n", arg);
616 static void cmd_list(const char *arg)
620 for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
621 GDBusProxy *proxy = list->data;
622 print_adapter(proxy, NULL);
626 static void cmd_show(const char *arg)
629 DBusMessageIter iter;
632 if (!arg || !strlen(arg)) {
633 if (check_default_ctrl() == FALSE)
636 proxy = default_ctrl;
638 proxy = find_proxy_by_address(ctrl_list, arg);
640 rl_printf("Controller %s not available\n", arg);
645 if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
648 dbus_message_iter_get_basic(&iter, &address);
649 rl_printf("Controller %s\n", address);
651 print_property(proxy, "Name");
652 print_property(proxy, "Alias");
653 print_property(proxy, "Class");
654 print_property(proxy, "Powered");
655 print_property(proxy, "Discoverable");
656 print_property(proxy, "Pairable");
658 print_property(proxy, "Modalias");
659 print_property(proxy, "Discovering");
660 #ifdef __TIZEN_PATCH__
661 print_property(proxy, "Advertising");
665 static void cmd_select(const char *arg)
669 if (!arg || !strlen(arg)) {
670 rl_printf("Missing controller address argument\n");
674 proxy = find_proxy_by_address(ctrl_list, arg);
676 rl_printf("Controller %s not available\n", arg);
680 if (default_ctrl == proxy)
683 default_ctrl = proxy;
684 print_adapter(proxy, NULL);
686 g_list_free(dev_list);
690 static void cmd_devices(const char *arg)
694 for (list = g_list_first(dev_list); list; list = g_list_next(list)) {
695 GDBusProxy *proxy = list->data;
696 print_device(proxy, NULL);
700 static void cmd_paired_devices(const char *arg)
704 for (list = g_list_first(dev_list); list; list = g_list_next(list)) {
705 GDBusProxy *proxy = list->data;
706 DBusMessageIter iter;
709 if (g_dbus_proxy_get_property(proxy, "Paired", &iter) == FALSE)
712 dbus_message_iter_get_basic(&iter, &paired);
716 print_device(proxy, NULL);
720 static void generic_callback(const DBusError *error, void *user_data)
722 char *str = user_data;
724 if (dbus_error_is_set(error))
725 rl_printf("Failed to set %s: %s\n", str, error->name);
727 rl_printf("Changing %s succeeded\n", str);
730 static void cmd_system_alias(const char *arg)
734 if (!arg || !strlen(arg)) {
735 rl_printf("Missing name argument\n");
739 if (check_default_ctrl() == FALSE)
742 name = g_strdup(arg);
744 if (g_dbus_proxy_set_property_basic(default_ctrl, "Alias",
745 DBUS_TYPE_STRING, &name,
746 generic_callback, name, g_free) == TRUE)
752 static void cmd_reset_alias(const char *arg)
756 if (check_default_ctrl() == FALSE)
761 if (g_dbus_proxy_set_property_basic(default_ctrl, "Alias",
762 DBUS_TYPE_STRING, &name,
763 generic_callback, name, g_free) == TRUE)
769 static void cmd_power(const char *arg)
774 if (parse_argument_on_off(arg, &powered) == FALSE)
777 if (check_default_ctrl() == FALSE)
780 str = g_strdup_printf("power %s", powered == TRUE ? "on" : "off");
782 if (g_dbus_proxy_set_property_basic(default_ctrl, "Powered",
783 DBUS_TYPE_BOOLEAN, &powered,
784 generic_callback, str, g_free) == TRUE)
790 static void cmd_pairable(const char *arg)
792 dbus_bool_t pairable;
795 if (parse_argument_on_off(arg, &pairable) == FALSE)
798 if (check_default_ctrl() == FALSE)
801 str = g_strdup_printf("pairable %s", pairable == TRUE ? "on" : "off");
803 if (g_dbus_proxy_set_property_basic(default_ctrl, "Pairable",
804 DBUS_TYPE_BOOLEAN, &pairable,
805 generic_callback, str, g_free) == TRUE)
811 static void cmd_discoverable(const char *arg)
813 dbus_bool_t discoverable;
816 if (parse_argument_on_off(arg, &discoverable) == FALSE)
819 if (check_default_ctrl() == FALSE)
822 str = g_strdup_printf("discoverable %s",
823 discoverable == TRUE ? "on" : "off");
825 if (g_dbus_proxy_set_property_basic(default_ctrl, "Discoverable",
826 DBUS_TYPE_BOOLEAN, &discoverable,
827 generic_callback, str, g_free) == TRUE)
833 static void cmd_agent(const char *arg)
836 const char *capability;
838 if (parse_argument_agent(arg, &enable, &capability) == FALSE)
841 if (enable == TRUE) {
842 g_free(auto_register_agent);
843 auto_register_agent = g_strdup(capability);
846 agent_register(dbus_conn, agent_manager,
847 auto_register_agent);
849 rl_printf("Agent registration enabled\n");
851 g_free(auto_register_agent);
852 auto_register_agent = NULL;
855 agent_unregister(dbus_conn, agent_manager);
857 rl_printf("Agent registration disabled\n");
861 static void cmd_default_agent(const char *arg)
863 agent_default(dbus_conn, agent_manager);
866 static void start_discovery_reply(DBusMessage *message, void *user_data)
868 dbus_bool_t enable = GPOINTER_TO_UINT(user_data);
871 dbus_error_init(&error);
873 if (dbus_set_error_from_message(&error, message) == TRUE) {
874 rl_printf("Failed to %s discovery: %s\n",
875 enable == TRUE ? "start" : "stop", error.name);
876 dbus_error_free(&error);
880 rl_printf("Discovery %s\n", enable == TRUE ? "started" : "stopped");
883 static void cmd_scan(const char *arg)
888 if (parse_argument_on_off(arg, &enable) == FALSE)
891 if (check_default_ctrl() == FALSE)
895 method = "StartDiscovery";
897 method = "StopDiscovery";
899 if (g_dbus_proxy_method_call(default_ctrl, method,
900 NULL, start_discovery_reply,
901 GUINT_TO_POINTER(enable), NULL) == FALSE) {
902 rl_printf("Failed to %s discovery\n",
903 enable == TRUE ? "start" : "stop");
908 static void append_variant(DBusMessageIter *iter, int type, void *val)
910 DBusMessageIter value;
911 char sig[2] = { type, '\0' };
913 dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
915 dbus_message_iter_append_basic(&value, type, val);
917 dbus_message_iter_close_container(iter, &value);
920 static void dict_append_entry(DBusMessageIter *dict, const char *key,
923 DBusMessageIter entry;
925 if (type == DBUS_TYPE_STRING) {
926 const char *str = *((const char **) val);
932 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
935 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
937 append_variant(&entry, type, val);
939 dbus_message_iter_close_container(dict, &entry);
942 #define DISTANCE_VAL_INVALID 0x7FFF
944 struct set_discovery_filter_args {
947 dbus_int16_t pathloss;
951 static void set_discovery_filter_setup(DBusMessageIter *iter,
954 struct set_discovery_filter_args *args = user_data;
955 DBusMessageIter dict;
957 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
958 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
959 DBUS_TYPE_STRING_AS_STRING
960 DBUS_TYPE_VARIANT_AS_STRING
961 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
963 if (args->uuids != NULL) {
964 DBusMessageIter entry, value, arrayIter;
965 char *uuids = "UUIDs";
968 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
971 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
974 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
977 dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, "s",
980 for (l = args->uuids; l != NULL; l = g_slist_next(l))
981 /* list->data contains string representation of uuid */
982 dbus_message_iter_append_basic(&arrayIter,
986 dbus_message_iter_close_container(&value, &arrayIter);
989 dbus_message_iter_close_container(&entry, &value);
992 dbus_message_iter_close_container(&dict, &entry);
995 if (args->pathloss != DISTANCE_VAL_INVALID)
996 dict_append_entry(&dict, "Pathloss", DBUS_TYPE_UINT16,
999 if (args->rssi != DISTANCE_VAL_INVALID)
1000 dict_append_entry(&dict, "RSSI", DBUS_TYPE_INT16, &args->rssi);
1002 if (args->transport != NULL)
1003 dict_append_entry(&dict, "Transport", DBUS_TYPE_STRING,
1006 dbus_message_iter_close_container(iter, &dict);
1010 static void set_discovery_filter_reply(DBusMessage *message,
1015 dbus_error_init(&error);
1016 if (dbus_set_error_from_message(&error, message) == TRUE) {
1017 rl_printf("SetDiscoveryFilter failed: %s\n", error.name);
1018 dbus_error_free(&error);
1022 rl_printf("SetDiscoveryFilter success\n");
1025 static gint filtered_scan_rssi = DISTANCE_VAL_INVALID;
1026 static gint filtered_scan_pathloss = DISTANCE_VAL_INVALID;
1027 static GSList *filtered_scan_uuids;
1028 static char *filtered_scan_transport;
1030 static void cmd_set_scan_filter_commit(void)
1032 struct set_discovery_filter_args args;
1035 args.pathloss = filtered_scan_pathloss;
1036 args.rssi = filtered_scan_rssi;
1037 args.transport = filtered_scan_transport;
1038 args.uuids = filtered_scan_uuids;
1040 if (check_default_ctrl() == FALSE)
1043 if (g_dbus_proxy_method_call(default_ctrl, "SetDiscoveryFilter",
1044 set_discovery_filter_setup, set_discovery_filter_reply,
1045 &args, NULL) == FALSE) {
1046 rl_printf("Failed to set discovery filter\n");
1051 static void cmd_set_scan_filter_uuids(const char *arg)
1053 char *uuid_str, *saveptr, *uuids, *uuidstmp;
1055 g_slist_free_full(filtered_scan_uuids, g_free);
1056 filtered_scan_uuids = NULL;
1058 if (!arg || !strlen(arg))
1061 uuids = g_strdup(arg);
1062 for (uuidstmp = uuids; ; uuidstmp = NULL) {
1063 uuid_str = strtok_r(uuidstmp, " \t", &saveptr);
1064 if (uuid_str == NULL)
1066 filtered_scan_uuids = g_slist_append(filtered_scan_uuids,
1072 cmd_set_scan_filter_commit();
1075 static void cmd_set_scan_filter_rssi(const char *arg)
1077 filtered_scan_pathloss = DISTANCE_VAL_INVALID;
1079 if (!arg || !strlen(arg))
1080 filtered_scan_rssi = DISTANCE_VAL_INVALID;
1082 filtered_scan_rssi = atoi(arg);
1084 cmd_set_scan_filter_commit();
1087 static void cmd_set_scan_filter_pathloss(const char *arg)
1089 filtered_scan_rssi = DISTANCE_VAL_INVALID;
1091 if (!arg || !strlen(arg))
1092 filtered_scan_pathloss = DISTANCE_VAL_INVALID;
1094 filtered_scan_pathloss = atoi(arg);
1096 cmd_set_scan_filter_commit();
1099 static void cmd_set_scan_filter_transport(const char *arg)
1101 g_free(filtered_scan_transport);
1103 if (!arg || !strlen(arg))
1104 filtered_scan_transport = NULL;
1106 filtered_scan_transport = g_strdup(arg);
1108 cmd_set_scan_filter_commit();
1111 static void cmd_set_scan_filter_clear(const char *arg)
1113 /* set default values for all options */
1114 filtered_scan_rssi = DISTANCE_VAL_INVALID;
1115 filtered_scan_pathloss = DISTANCE_VAL_INVALID;
1116 g_slist_free_full(filtered_scan_uuids, g_free);
1117 filtered_scan_uuids = NULL;
1118 g_free(filtered_scan_transport);
1119 filtered_scan_transport = NULL;
1121 cmd_set_scan_filter_commit();
1124 static struct GDBusProxy *find_device(const char *arg)
1128 if (!arg || !strlen(arg)) {
1131 rl_printf("Missing device address argument\n");
1135 proxy = find_proxy_by_address(dev_list, arg);
1137 rl_printf("Device %s not available\n", arg);
1144 static void cmd_info(const char *arg)
1147 DBusMessageIter iter;
1148 const char *address;
1150 proxy = find_device(arg);
1154 if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
1157 dbus_message_iter_get_basic(&iter, &address);
1158 rl_printf("Device %s\n", address);
1160 print_property(proxy, "Name");
1161 print_property(proxy, "Alias");
1162 print_property(proxy, "Class");
1163 print_property(proxy, "Appearance");
1164 print_property(proxy, "Icon");
1165 print_property(proxy, "Paired");
1166 print_property(proxy, "Trusted");
1167 print_property(proxy, "Blocked");
1168 print_property(proxy, "Connected");
1169 print_property(proxy, "LegacyPairing");
1171 print_property(proxy, "Modalias");
1172 #ifdef __TIZEN_PATCH__
1173 print_property(proxy, "Flag");
1174 print_property(proxy, "ManufacturerDataLen");
1176 print_property(proxy, "ManufacturerData");
1177 print_property(proxy, "ServiceData");
1178 print_property(proxy, "RSSI");
1179 print_property(proxy, "TxPower");
1182 static void pair_reply(DBusMessage *message, void *user_data)
1186 dbus_error_init(&error);
1188 if (dbus_set_error_from_message(&error, message) == TRUE) {
1189 rl_printf("Failed to pair: %s\n", error.name);
1190 dbus_error_free(&error);
1194 rl_printf("Pairing successful\n");
1197 static void cmd_pair(const char *arg)
1201 proxy = find_device(arg);
1205 if (g_dbus_proxy_method_call(proxy, "Pair", NULL, pair_reply,
1206 NULL, NULL) == FALSE) {
1207 rl_printf("Failed to pair\n");
1211 rl_printf("Attempting to pair with %s\n", arg);
1214 static void cmd_trust(const char *arg)
1217 dbus_bool_t trusted;
1220 proxy = find_device(arg);
1226 str = g_strdup_printf("%s trust", arg);
1228 if (g_dbus_proxy_set_property_basic(proxy, "Trusted",
1229 DBUS_TYPE_BOOLEAN, &trusted,
1230 generic_callback, str, g_free) == TRUE)
1236 static void cmd_untrust(const char *arg)
1239 dbus_bool_t trusted;
1242 proxy = find_device(arg);
1248 str = g_strdup_printf("%s untrust", arg);
1250 if (g_dbus_proxy_set_property_basic(proxy, "Trusted",
1251 DBUS_TYPE_BOOLEAN, &trusted,
1252 generic_callback, str, g_free) == TRUE)
1258 static void cmd_block(const char *arg)
1261 dbus_bool_t blocked;
1264 proxy = find_device(arg);
1270 str = g_strdup_printf("%s block", arg);
1272 if (g_dbus_proxy_set_property_basic(proxy, "Blocked",
1273 DBUS_TYPE_BOOLEAN, &blocked,
1274 generic_callback, str, g_free) == TRUE)
1280 static void cmd_unblock(const char *arg)
1283 dbus_bool_t blocked;
1286 proxy = find_device(arg);
1292 str = g_strdup_printf("%s unblock", arg);
1294 if (g_dbus_proxy_set_property_basic(proxy, "Blocked",
1295 DBUS_TYPE_BOOLEAN, &blocked,
1296 generic_callback, str, g_free) == TRUE)
1302 static void remove_device_reply(DBusMessage *message, void *user_data)
1306 dbus_error_init(&error);
1308 if (dbus_set_error_from_message(&error, message) == TRUE) {
1309 rl_printf("Failed to remove device: %s\n", error.name);
1310 dbus_error_free(&error);
1314 rl_printf("Device has been removed\n");
1317 static void remove_device_setup(DBusMessageIter *iter, void *user_data)
1319 const char *path = user_data;
1321 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
1324 static void cmd_remove(const char *arg)
1329 if (!arg || !strlen(arg)) {
1330 rl_printf("Missing device address argument\n");
1334 if (check_default_ctrl() == FALSE)
1337 proxy = find_proxy_by_address(dev_list, arg);
1339 rl_printf("Device %s not available\n", arg);
1343 path = g_strdup(g_dbus_proxy_get_path(proxy));
1345 if (g_dbus_proxy_method_call(default_ctrl, "RemoveDevice",
1346 remove_device_setup,
1347 remove_device_reply,
1348 path, g_free) == FALSE) {
1349 rl_printf("Failed to remove device\n");
1355 static void connect_reply(DBusMessage *message, void *user_data)
1357 GDBusProxy *proxy = user_data;
1360 dbus_error_init(&error);
1362 if (dbus_set_error_from_message(&error, message) == TRUE) {
1363 rl_printf("Failed to connect: %s\n", error.name);
1364 dbus_error_free(&error);
1368 rl_printf("Connection successful\n");
1370 set_default_device(proxy, NULL);
1373 static void cmd_connect(const char *arg)
1377 if (!arg || !strlen(arg)) {
1378 rl_printf("Missing device address argument\n");
1382 proxy = find_proxy_by_address(dev_list, arg);
1384 rl_printf("Device %s not available\n", arg);
1388 if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,
1389 proxy, NULL) == FALSE) {
1390 rl_printf("Failed to connect\n");
1394 rl_printf("Attempting to connect to %s\n", arg);
1397 static void disconn_reply(DBusMessage *message, void *user_data)
1399 GDBusProxy *proxy = user_data;
1402 dbus_error_init(&error);
1404 if (dbus_set_error_from_message(&error, message) == TRUE) {
1405 rl_printf("Failed to disconnect: %s\n", error.name);
1406 dbus_error_free(&error);
1410 rl_printf("Successful disconnected\n");
1412 if (proxy != default_dev)
1415 set_default_device(NULL, NULL);
1418 static void cmd_disconn(const char *arg)
1422 proxy = find_device(arg);
1426 if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, disconn_reply,
1427 proxy, NULL) == FALSE) {
1428 rl_printf("Failed to disconnect\n");
1431 if (strlen(arg) == 0) {
1432 DBusMessageIter iter;
1434 if (g_dbus_proxy_get_property(proxy, "Address", &iter) == TRUE)
1435 dbus_message_iter_get_basic(&iter, &arg);
1437 rl_printf("Attempting to disconnect from %s\n", arg);
1440 static void cmd_list_attributes(const char *arg)
1444 proxy = find_device(arg);
1448 gatt_list_attributes(g_dbus_proxy_get_path(proxy));
1451 static void cmd_select_attribute(const char *arg)
1455 if (!arg || !strlen(arg)) {
1456 rl_printf("Missing attribute argument\n");
1461 rl_printf("No device connected\n");
1465 proxy = gatt_select_attribute(arg);
1467 set_default_attribute(proxy);
1470 static struct GDBusProxy *find_attribute(const char *arg)
1474 if (!arg || !strlen(arg)) {
1476 return default_attr;
1477 rl_printf("Missing attribute argument\n");
1481 proxy = gatt_select_attribute(arg);
1483 rl_printf("Attribute %s not available\n", arg);
1490 static void cmd_attribute_info(const char *arg)
1493 DBusMessageIter iter;
1494 const char *iface, *uuid, *text;
1496 proxy = find_attribute(arg);
1500 if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
1503 dbus_message_iter_get_basic(&iter, &uuid);
1505 text = uuidstr_to_str(uuid);
1507 text = g_dbus_proxy_get_path(proxy);
1509 iface = g_dbus_proxy_get_interface(proxy);
1510 if (!strcmp(iface, "org.bluez.GattService1")) {
1511 rl_printf("Service - %s\n", text);
1513 print_property(proxy, "UUID");
1514 print_property(proxy, "Primary");
1515 print_property(proxy, "Characteristics");
1516 print_property(proxy, "Includes");
1517 } else if (!strcmp(iface, "org.bluez.GattCharacteristic1")) {
1518 rl_printf("Characteristic - %s\n", text);
1520 print_property(proxy, "UUID");
1521 print_property(proxy, "Service");
1522 print_property(proxy, "Value");
1523 print_property(proxy, "Notifying");
1524 print_property(proxy, "Flags");
1525 print_property(proxy, "Descriptors");
1526 } else if (!strcmp(iface, "org.bluez.GattDescriptor1")) {
1527 rl_printf("Descriptor - %s\n", text);
1529 print_property(proxy, "UUID");
1530 print_property(proxy, "Characteristic");
1531 print_property(proxy, "Value");
1535 static void cmd_read(const char *arg)
1537 if (!default_attr) {
1538 rl_printf("No attribute selected\n");
1542 gatt_read_attribute(default_attr);
1545 static void cmd_write(const char *arg)
1547 if (!arg || !strlen(arg)) {
1548 rl_printf("Missing data argument\n");
1552 if (!default_attr) {
1553 rl_printf("No attribute selected\n");
1557 gatt_write_attribute(default_attr, arg);
1560 static void cmd_notify(const char *arg)
1564 if (parse_argument_on_off(arg, &enable) == FALSE)
1567 if (!default_attr) {
1568 rl_printf("No attribute selected\n");
1572 gatt_notify_attribute(default_attr, enable ? true : false);
1575 static void cmd_register_profile(const char *arg)
1579 if (check_default_ctrl() == FALSE)
1582 if (wordexp(arg, &w, WRDE_NOCMD)) {
1583 rl_printf("Invalid argument\n");
1587 if (w.we_wordc == 0) {
1588 rl_printf("Missing argument\n");
1592 gatt_register_profile(dbus_conn, default_ctrl, &w);
1597 static void cmd_unregister_profile(const char *arg)
1599 if (check_default_ctrl() == FALSE)
1602 gatt_unregister_profile(dbus_conn, default_ctrl);
1605 static void cmd_version(const char *arg)
1607 rl_printf("Version %s\n", VERSION);
1610 static void cmd_quit(const char *arg)
1612 g_main_loop_quit(main_loop);
1615 static char *generic_generator(const char *text, int state,
1616 GList *source, const char *property)
1618 static int index, len;
1626 for (list = g_list_nth(source, index); list;
1627 list = g_list_next(list)) {
1628 GDBusProxy *proxy = list->data;
1629 DBusMessageIter iter;
1634 if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE)
1637 dbus_message_iter_get_basic(&iter, &str);
1639 if (!strncmp(str, text, len))
1646 static char *ctrl_generator(const char *text, int state)
1648 return generic_generator(text, state, ctrl_list, "Address");
1651 static char *dev_generator(const char *text, int state)
1653 return generic_generator(text, state, dev_list, "Address");
1656 static char *attribute_generator(const char *text, int state)
1658 return gatt_attribute_generator(text, state);
1661 static char *capability_generator(const char *text, int state)
1663 static int index, len;
1671 while ((arg = agent_arguments[index])) {
1674 if (!strncmp(arg, text, len))
1681 static const struct {
1684 void (*func) (const char *arg);
1686 char * (*gen) (const char *text, int state);
1687 void (*disp) (char **matches, int num_matches, int max_length);
1689 { "list", NULL, cmd_list, "List available controllers" },
1690 { "show", "[ctrl]", cmd_show, "Controller information",
1692 { "select", "<ctrl>", cmd_select, "Select default controller",
1694 { "devices", NULL, cmd_devices, "List available devices" },
1695 { "paired-devices", NULL, cmd_paired_devices,
1696 "List paired devices"},
1697 { "system-alias", "<name>", cmd_system_alias },
1698 { "reset-alias", NULL, cmd_reset_alias },
1699 { "power", "<on/off>", cmd_power, "Set controller power" },
1700 { "pairable", "<on/off>", cmd_pairable,
1701 "Set controller pairable mode" },
1702 { "discoverable", "<on/off>", cmd_discoverable,
1703 "Set controller discoverable mode" },
1704 { "agent", "<on/off/capability>", cmd_agent,
1705 "Enable/disable agent with given capability",
1706 capability_generator},
1707 { "default-agent",NULL, cmd_default_agent,
1708 "Set agent as the default one" },
1709 { "set-scan-filter-uuids", "[uuid1 uuid2 ...]",
1710 cmd_set_scan_filter_uuids, "Set scan filter uuids" },
1711 { "set-scan-filter-rssi", "[rssi]", cmd_set_scan_filter_rssi,
1712 "Set scan filter rssi, and clears pathloss" },
1713 { "set-scan-filter-pathloss", "[pathloss]",
1714 cmd_set_scan_filter_pathloss,
1715 "Set scan filter pathloss, and clears rssi" },
1716 { "set-scan-filter-transport", "[transport]",
1717 cmd_set_scan_filter_transport, "Set scan filter transport" },
1718 { "set-scan-filter-clear", "", cmd_set_scan_filter_clear,
1719 "Clears discovery filter." },
1720 { "scan", "<on/off>", cmd_scan, "Scan for devices" },
1721 { "info", "[dev]", cmd_info, "Device information",
1723 { "pair", "[dev]", cmd_pair, "Pair with device",
1725 { "trust", "[dev]", cmd_trust, "Trust device",
1727 { "untrust", "[dev]", cmd_untrust, "Untrust device",
1729 { "block", "[dev]", cmd_block, "Block device",
1731 { "unblock", "[dev]", cmd_unblock, "Unblock device",
1733 { "remove", "<dev>", cmd_remove, "Remove device",
1735 { "connect", "<dev>", cmd_connect, "Connect device",
1737 { "disconnect", "[dev]", cmd_disconn, "Disconnect device",
1739 { "list-attributes", "[dev]", cmd_list_attributes, "List attributes",
1741 { "select-attribute", "<attribute>", cmd_select_attribute,
1742 "Select attribute", attribute_generator },
1743 { "attribute-info", "[attribute]", cmd_attribute_info,
1744 "Select attribute", attribute_generator },
1745 { "read", NULL, cmd_read, "Read attribute value" },
1746 { "write", "<data=[xx xx ...]>", cmd_write,
1747 "Write attribute value" },
1748 { "notify", "<on/off>", cmd_notify, "Notify attribute value" },
1749 { "register-profile", "<UUID ...>", cmd_register_profile,
1750 "Register profile to connect" },
1751 { "unregister-profile", NULL, cmd_unregister_profile,
1752 "Unregister profile" },
1753 { "version", NULL, cmd_version, "Display version" },
1754 { "quit", NULL, cmd_quit, "Quit program" },
1755 { "exit", NULL, cmd_quit },
1760 static char *cmd_generator(const char *text, int state)
1762 static int index, len;
1770 while ((cmd = cmd_table[index].cmd)) {
1773 if (!strncmp(cmd, text, len))
1780 static char **cmd_completion(const char *text, int start, int end)
1782 char **matches = NULL;
1784 if (agent_completion() == TRUE) {
1785 rl_attempted_completion_over = 1;
1792 for (i = 0; cmd_table[i].cmd; i++) {
1793 if (strncmp(cmd_table[i].cmd,
1794 rl_line_buffer, start - 1))
1797 if (!cmd_table[i].gen)
1800 rl_completion_display_matches_hook = cmd_table[i].disp;
1801 matches = rl_completion_matches(text, cmd_table[i].gen);
1805 rl_completion_display_matches_hook = NULL;
1806 matches = rl_completion_matches(text, cmd_generator);
1810 rl_attempted_completion_over = 1;
1815 static void rl_handler(char *input)
1821 rl_insert_text("quit");
1824 g_main_loop_quit(main_loop);
1831 if (agent_input(dbus_conn, input) == TRUE)
1836 cmd = strtok_r(input, " ", &arg);
1841 int len = strlen(arg);
1842 if (len > 0 && arg[len - 1] == ' ')
1843 arg[len - 1] = '\0';
1846 for (i = 0; cmd_table[i].cmd; i++) {
1847 if (strcmp(cmd, cmd_table[i].cmd))
1850 if (cmd_table[i].func) {
1851 cmd_table[i].func(arg);
1856 if (strcmp(cmd, "help")) {
1857 printf("Invalid command\n");
1861 printf("Available commands:\n");
1863 for (i = 0; cmd_table[i].cmd; i++) {
1864 if (cmd_table[i].desc)
1865 printf(" %s %-*s %s\n", cmd_table[i].cmd,
1866 (int)(25 - strlen(cmd_table[i].cmd)),
1867 cmd_table[i].arg ? : "",
1868 cmd_table[i].desc ? : "");
1875 static gboolean input_handler(GIOChannel *channel, GIOCondition condition,
1878 if (condition & G_IO_IN) {
1879 rl_callback_read_char();
1883 if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
1884 g_main_loop_quit(main_loop);
1891 static guint setup_standard_input(void)
1893 GIOChannel *channel;
1896 channel = g_io_channel_unix_new(fileno(stdin));
1898 source = g_io_add_watch(channel,
1899 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
1900 input_handler, NULL);
1902 g_io_channel_unref(channel);
1907 static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
1910 static bool terminated = false;
1911 struct signalfd_siginfo si;
1915 if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
1916 g_main_loop_quit(main_loop);
1920 fd = g_io_channel_unix_get_fd(channel);
1922 result = read(fd, &si, sizeof(si));
1923 if (result != sizeof(si))
1926 switch (si.ssi_signo) {
1929 rl_replace_line("", 0);
1937 * If input was not yet setup up that means signal was received
1938 * while daemon was not yet running. Since user is not able
1939 * to terminate client by CTRL-D or typing exit treat this as
1940 * exit and fall through.
1944 rl_replace_line("", 0);
1946 g_main_loop_quit(main_loop);
1956 static guint setup_signalfd(void)
1958 GIOChannel *channel;
1964 sigaddset(&mask, SIGINT);
1965 sigaddset(&mask, SIGTERM);
1967 if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
1968 perror("Failed to set signal mask");
1972 fd = signalfd(-1, &mask, 0);
1974 perror("Failed to create signal descriptor");
1978 channel = g_io_channel_unix_new(fd);
1980 g_io_channel_set_close_on_unref(channel, TRUE);
1981 g_io_channel_set_encoding(channel, NULL, NULL);
1982 g_io_channel_set_buffered(channel, FALSE);
1984 source = g_io_add_watch(channel,
1985 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
1986 signal_handler, NULL);
1988 g_io_channel_unref(channel);
1993 static gboolean option_version = FALSE;
1995 static gboolean parse_agent(const char *key, const char *value,
1996 gpointer user_data, GError **error)
1999 auto_register_agent = g_strdup(value);
2001 auto_register_agent = g_strdup("");
2006 static GOptionEntry options[] = {
2007 { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
2008 "Show version information and exit" },
2009 { "agent", 'a', G_OPTION_FLAG_OPTIONAL_ARG,
2010 G_OPTION_ARG_CALLBACK, parse_agent,
2011 "Register agent handler", "CAPABILITY" },
2015 static void client_ready(GDBusClient *client, void *user_data)
2017 guint *input = user_data;
2019 *input = setup_standard_input();
2022 int main(int argc, char *argv[])
2024 GOptionContext *context;
2025 GError *error = NULL;
2026 GDBusClient *client;
2029 context = g_option_context_new(NULL);
2030 g_option_context_add_main_entries(context, options, NULL);
2032 if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
2033 if (error != NULL) {
2034 g_printerr("%s\n", error->message);
2035 g_error_free(error);
2037 g_printerr("An unknown error occurred\n");
2041 g_option_context_free(context);
2043 if (option_version == TRUE) {
2044 printf("%s\n", VERSION);
2048 main_loop = g_main_loop_new(NULL, FALSE);
2049 dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
2051 rl_attempted_completion_function = cmd_completion;
2053 rl_erase_empty_line = 1;
2054 rl_callback_handler_install(NULL, rl_handler);
2056 rl_set_prompt(PROMPT_OFF);
2059 signal = setup_signalfd();
2060 client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
2062 g_dbus_client_set_connect_watch(client, connect_handler, NULL);
2063 g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
2064 g_dbus_client_set_signal_watch(client, message_handler, NULL);
2066 g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
2067 property_changed, NULL);
2070 g_dbus_client_set_ready_watch(client, client_ready, &input);
2072 g_main_loop_run(main_loop);
2074 g_dbus_client_unref(client);
2075 g_source_remove(signal);
2077 g_source_remove(input);
2080 rl_callback_handler_remove();
2082 dbus_connection_unref(dbus_conn);
2083 g_main_loop_unref(main_loop);
2085 g_list_free_full(ctrl_list, proxy_leak);
2086 g_list_free_full(dev_list, proxy_leak);
2088 g_free(auto_register_agent);