On Tue, 2011-05-10 at 19:20 +0100, Bastien Nocera wrote: <snip> > And a patch with inotify support (easier than I remembered). > > That leaves us with the problem of changing the name when the default > adapter changes. Tested and a few corrections added. - Made the inotify code work (oops) - Make adapter_update_local_name() actually update the adapter's name if it's up - Factor out the "SetName" method (note that we don't check whether it's valid UTF-8 anymore, because D-Bus will kick out the client if the string isn't UTF-8 anyway) What's left to do is: - initial naming (the default_adapter isn't set on startup, so the first adapter is always named "Foo #1" instead of "Foo") - name changes when the default adapter changes (although I could certainly live without that one for now) Comments appreciated. I'm more than willing to split out the src/adapter.[ch] and src/manager.[ch] changes, just let me know. Cheers
>From ed8540cf729b06166240faa869fdce4103c420b3 Mon Sep 17 00:00:00 2001 From: Bastien Nocera <hadess@xxxxxxxxxx> Date: Tue, 10 May 2011 18:02:14 +0100 Subject: [PATCH] adaptername: Move adapter naming into a plugin Moving the adapter naming allows us to use the /etc/machine-info [1] pretty hostname, as implemented by hostnamed [2] in systemd. If /etc/machine-info is not present, the adapter name stored on disk in /var/lib/bluetooth will be used. If no adapter name has been set yet, the default from the main.conf will be used. [1]: http://0pointer.de/public/systemd-man/machine-info.html [2]: http://www.freedesktop.org/wiki/Software/systemd/hostnamed TODO: * Changing the adapter name when the default changes --- Makefile.am | 3 + configure.ac | 3 + plugins/adaptername.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++++ src/adapter.c | 107 +++---------------- src/adapter.h | 2 +- src/manager.c | 5 + src/manager.h | 1 + 7 files changed, 318 insertions(+), 92 deletions(-) create mode 100644 plugins/adaptername.c diff --git a/Makefile.am b/Makefile.am index caffbe2..fe24883 100644 --- a/Makefile.am +++ b/Makefile.am @@ -218,6 +218,9 @@ EXTRA_DIST += plugins/hal.c plugins/formfactor.c builtin_modules += storage builtin_sources += plugins/storage.c +builtin_modules += adaptername +builtin_sources += plugins/adaptername.c + if MAEMO6PLUGIN builtin_modules += maemo6 builtin_sources += plugins/maemo6.c diff --git a/configure.ac b/configure.ac index 111ff01..4c6016a 100644 --- a/configure.ac +++ b/configure.ac @@ -35,6 +35,9 @@ AC_FUNC_PPOLL AC_CHECK_LIB(dl, dlopen, dummy=yes, AC_MSG_ERROR(dynamic linking loader is required)) +AC_CHECK_HEADER([sys/inotify.h], + [AC_DEFINE([HAVE_SYS_INOTIFY_H], 1, + [Define to 1 if you have <sys/inotify.h>.])]) AC_PATH_DBUS AC_PATH_GLIB AC_PATH_ALSA diff --git a/plugins/adaptername.c b/plugins/adaptername.c new file mode 100644 index 0000000..33c4933 --- /dev/null +++ b/plugins/adaptername.c @@ -0,0 +1,289 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2010 Marcel Holtmann <marcel@xxxxxxxxxxxx> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> + +#include <glib.h> +#include <bluetooth/bluetooth.h> + +#include "plugin.h" +#include "hcid.h" /* For main_opts */ +#include "adapter.h" +#include "manager.h" +#include "device.h" /* Needed for storage.h */ +#include "storage.h" +#include "log.h" + +#ifdef HAVE_SYS_INOTIFY_H +#include <sys/inotify.h> +#define EVENT_SIZE (sizeof (struct inotify_event)) +#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16)) +#endif + +#define MACHINE_INFO_DIR "/etc/" +#define MACHINE_INFO_FILE "machine-info" + +#ifdef HAVE_SYS_INOTIFY_H +static GIOChannel *inotify = NULL; +static int watch_fd = -1; +#endif + +/* This file is part of systemd's hostnamed functionality: + * http://0pointer.de/public/systemd-man/machine-info.html + * http://www.freedesktop.org/wiki/Software/systemd/hostnamed + */ +static char *read_pretty_host_name (void) +{ + char *contents, *ret; + char **lines; + guint i; + + ret = NULL; + + if (g_file_get_contents(MACHINE_INFO_DIR MACHINE_INFO_FILE, + &contents, NULL, NULL) == FALSE) { + return NULL; + } + lines = g_strsplit_set(contents, "\r\n", 0); + g_free(contents); + + if (lines == NULL) + return NULL; + + for (i = 0; lines[i] != NULL; i++) { + if (g_str_has_prefix(lines[i], "PRETTY_HOSTNAME=")) { + ret = g_strdup(lines[i] + strlen("PRETTY_HOSTNAME=")); + break; + } + } + + g_strfreev(lines); + return ret; +} + +/* + * Device name expansion + * %d - device id + * %h - hostname + */ +static char *expand_name(char *dst, int size, char *str, int dev_id) +{ + register int sp, np, olen; + char *opt, buf[10]; + + if (!str || !dst) + return NULL; + + sp = np = 0; + while (np < size - 1 && str[sp]) { + switch (str[sp]) { + case '%': + opt = NULL; + + switch (str[sp+1]) { + case 'd': + sprintf(buf, "%d", dev_id); + opt = buf; + break; + + case 'h': + opt = main_opts.host_name; + break; + + case '%': + dst[np++] = str[sp++]; + /* fall through */ + default: + sp++; + continue; + } + + if (opt) { + /* substitute */ + olen = strlen(opt); + if (np + olen < size - 1) + memcpy(dst + np, opt, olen); + np += olen; + } + sp += 2; + continue; + + case '\\': + sp++; + /* fall through */ + default: + dst[np++] = str[sp++]; + break; + } + } + dst[np] = '\0'; + return dst; +} + +static int adaptername_probe(struct btd_adapter *adapter) +{ + int current_id; + char name[MAX_NAME_LENGTH + 1]; + char *pretty_hostname; + bdaddr_t bdaddr; + + current_id = adapter_get_dev_id(adapter); + + pretty_hostname = read_pretty_host_name(); + if (pretty_hostname != NULL) { + int default_adapter; + + default_adapter = manager_get_default_adapter(); + + if (default_adapter != current_id) { + char *str; + + /* +1 because we don't want an adapter called "Foobar's laptop #0" */ + str = g_strdup_printf ("%s #%d", pretty_hostname, current_id + 1); + DBG("Setting name '%s' for device 'hci%d'", str, current_id); + + adapter_update_local_name(adapter, str); + g_free(str); + } else { + DBG("Setting name '%s' for device 'hci%d'", pretty_hostname, current_id); + adapter_update_local_name(adapter, pretty_hostname); + } + g_free(pretty_hostname); + + return 0; + } + + adapter_get_address(adapter, &bdaddr); + + if (read_local_name(&bdaddr, name) < 0) { + expand_name(name, MAX_NAME_LENGTH, main_opts.name, + current_id); + } + DBG("Setting name '%s' for device 'hci%d'", name, current_id); + adapter_update_local_name(adapter, name); + + return 0; +} + +static gboolean handle_inotify_cb(GIOChannel *channel, + GIOCondition condition, gpointer data) +{ + char buf[EVENT_BUF_LEN]; + GIOStatus err; + gsize len, i; + gboolean changed; + + changed = FALSE; + + err = g_io_channel_read_chars(channel, buf, EVENT_BUF_LEN, &len, NULL); + if (err != G_IO_STATUS_NORMAL) { + error("Error reading inotify event: %d\n", err); + return FALSE; + } + + i = 0; + while (i < len) { + struct inotify_event *pevent = (struct inotify_event *) & buf[i]; + + /* check that it's ours */ + if (pevent->len && + pevent->name != NULL && + strcmp(pevent->name, MACHINE_INFO_FILE) == 0) { + changed = TRUE; + } + i += EVENT_SIZE + pevent->len; + } + + if (changed != FALSE) { + DBG(MACHINE_INFO_DIR MACHINE_INFO_FILE + " changed, changing names for adapters"); + manager_foreach_adapter ((adapter_cb) adaptername_probe, NULL); + } + + return TRUE; +} + +static void adaptername_remove(struct btd_adapter *adapter) +{ +#ifdef HAVE_SYS_INOTIFY_H + if (watch_fd >= 0) + close (watch_fd); + if (inotify != NULL) + g_io_channel_shutdown(inotify, FALSE, NULL); +#endif /* HAVE_SYS_INOTIFY_H */ +} + +static struct btd_adapter_driver adaptername_driver = { + .name = "adaptername", + .probe = adaptername_probe, + .remove = adaptername_remove, +}; + +static int adaptername_init(void) +{ + int ret; + + ret = btd_register_adapter_driver(&adaptername_driver); +#ifdef HAVE_SYS_INOTIFY_H + if (ret == 0) { + int inot_fd; + + inot_fd = inotify_init(); + if (inot_fd < 0) { + error("Failed to setup inotify"); + return 0; + } + watch_fd = inotify_add_watch(inot_fd, + MACHINE_INFO_DIR, + IN_CLOSE_WRITE | IN_DELETE | IN_CREATE); + if (watch_fd < 0) { + error("Failed to setup watch for '%s'", + MACHINE_INFO_DIR); + return 0; + } + + inotify = g_io_channel_unix_new(inot_fd); + g_io_channel_set_close_on_unref(inotify, TRUE); + g_io_channel_set_encoding (inotify, NULL, NULL); + g_io_channel_set_flags (inotify, G_IO_FLAG_NONBLOCK, NULL); + g_io_add_watch(inotify, G_IO_IN, handle_inotify_cb, NULL); + + return 0; + } +#endif /* HAVE_SYS_INOTIFY_H */ + return ret; +} + +static void adaptername_exit(void) +{ + btd_unregister_adapter_driver(&adaptername_driver); +} + +BLUETOOTH_PLUGIN_DEFINE(adaptername, VERSION, + BLUETOOTH_PLUGIN_PRIORITY_LOW, adaptername_init, adaptername_exit) diff --git a/src/adapter.c b/src/adapter.c index 76fc01b..09bbf06 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -181,64 +181,6 @@ static void dev_info_free(struct remote_dev_info *dev) g_free(dev); } -/* - * Device name expansion - * %d - device id - */ -static char *expand_name(char *dst, int size, char *str, int dev_id) -{ - register int sp, np, olen; - char *opt, buf[10]; - - if (!str || !dst) - return NULL; - - sp = np = 0; - while (np < size - 1 && str[sp]) { - switch (str[sp]) { - case '%': - opt = NULL; - - switch (str[sp+1]) { - case 'd': - sprintf(buf, "%d", dev_id); - opt = buf; - break; - - case 'h': - opt = main_opts.host_name; - break; - - case '%': - dst[np++] = str[sp++]; - /* fall through */ - default: - sp++; - continue; - } - - if (opt) { - /* substitute */ - olen = strlen(opt); - if (np + olen < size - 1) - memcpy(dst + np, opt, olen); - np += olen; - } - sp += 2; - continue; - - case '\\': - sp++; - /* fall through */ - default: - dst[np++] = str[sp++]; - break; - } - } - dst[np] = '\0'; - return dst; -} - int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major, uint8_t minor) { @@ -915,10 +857,10 @@ void btd_adapter_class_changed(struct btd_adapter *adapter, uint32_t new_class) DBUS_TYPE_UINT32, &new_class); } -void adapter_update_local_name(struct btd_adapter *adapter, const char *name) +int adapter_update_local_name(struct btd_adapter *adapter, const char *name) { if (strncmp(name, adapter->name, MAX_NAME_LENGTH) == 0) - return; + return 0; strncpy(adapter->name, name, MAX_NAME_LENGTH); @@ -937,38 +879,29 @@ void adapter_update_local_name(struct btd_adapter *adapter, const char *name) DBUS_TYPE_STRING, &name_ptr); } + if (adapter->up) { + int err = adapter_ops->set_name(adapter->dev_id, name); + if (err < 0) + return -err; + + adapter->name_stored = TRUE; + } + adapter->name_stored = FALSE; + + return 0; } static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg, const char *name, void *data) { struct btd_adapter *adapter = data; - char *name_ptr = adapter->name; - - if (!g_utf8_validate(name, -1, NULL)) { - error("Name change failed: supplied name isn't valid UTF-8"); - return btd_error_invalid_args(msg); - } - - if (strncmp(name, adapter->name, MAX_NAME_LENGTH) == 0) - goto done; - - strncpy(adapter->name, name, MAX_NAME_LENGTH); - write_local_name(&adapter->bdaddr, name); - emit_property_changed(connection, adapter->path, - ADAPTER_INTERFACE, "Name", - DBUS_TYPE_STRING, &name_ptr); - - if (adapter->up) { - int err = adapter_ops->set_name(adapter->dev_id, name); - if (err < 0) - return btd_error_failed(msg, strerror(-err)); + int err; - adapter->name_stored = TRUE; - } + err = adapter_update_local_name (adapter, name); + if (err < 0) + return btd_error_failed(msg, strerror(err)); -done: return dbus_message_new_method_return(msg); } @@ -2580,14 +2513,6 @@ gboolean adapter_init(struct btd_adapter *adapter) return FALSE; } - if (read_local_name(&adapter->bdaddr, adapter->name) < 0) - expand_name(adapter->name, MAX_NAME_LENGTH, main_opts.name, - adapter->dev_id); - - if (main_opts.attrib_server) - attrib_gap_set(GATT_CHARAC_DEVICE_NAME, - (const uint8_t *) adapter->name, strlen(adapter->name)); - sdp_init_services_list(&adapter->bdaddr); load_drivers(adapter); clear_blocked(adapter); diff --git a/src/adapter.h b/src/adapter.h index 9406b9b..8635400 100644 --- a/src/adapter.h +++ b/src/adapter.h @@ -127,7 +127,7 @@ int adapter_remove_found_device(struct btd_adapter *adapter, bdaddr_t *bdaddr); void adapter_emit_device_found(struct btd_adapter *adapter, struct remote_dev_info *dev); void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode); -void adapter_update_local_name(struct btd_adapter *adapter, const char *name); +int adapter_update_local_name(struct btd_adapter *adapter, const char *name); void adapter_service_insert(struct btd_adapter *adapter, void *rec); void adapter_service_remove(struct btd_adapter *adapter, void *rec); void btd_adapter_class_changed(struct btd_adapter *adapter, diff --git a/src/manager.c b/src/manager.c index e805e0c..dedec8b 100644 --- a/src/manager.c +++ b/src/manager.c @@ -288,6 +288,11 @@ static void manager_remove_adapter(struct btd_adapter *adapter) btd_start_exit_timer(); } +int manager_get_default_adapter (void) +{ + return default_adapter_id; +} + void manager_cleanup(DBusConnection *conn, const char *path) { g_slist_foreach(adapters, (GFunc) manager_remove_adapter, NULL); diff --git a/src/manager.h b/src/manager.h index 05c38b3..90d3690 100644 --- a/src/manager.h +++ b/src/manager.h @@ -41,3 +41,4 @@ struct btd_adapter *btd_manager_register_adapter(int id); int btd_manager_unregister_adapter(int id); void manager_add_adapter(const char *path); void btd_manager_set_did(uint16_t vendor, uint16_t product, uint16_t version); +int manager_get_default_adapter (void); -- 1.7.5.1