On Thu, 2011-05-26 at 15:11 +0100, Bastien Nocera wrote: > As discussed on IRC, > > inotify is now required, and we force hci0 (or the first device) to be > named after the pretty hostname. > > Note that the GATT call isn't removed, it's now done in > adapter_update_local_name(). As discussed again, removed the default adapter special casing, and we'll just call hci0 with the pretty name.
>From 2ddb830390100b6614be228331635d2e3fc9b9d8 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. If a pretty name is available, hci0 will be using this name, and further adapters will have a number appended. [1]: http://0pointer.de/public/systemd-man/machine-info.html [2]: http://www.freedesktop.org/wiki/Software/systemd/hostnamed --- Makefile.am | 3 + configure.ac | 4 + plugins/adaptername.c | 279 +++++++++++++++++++++++++++++++++++++++++++++++++ src/adapter.c | 107 +++---------------- src/adapter.h | 2 +- 5 files changed, 303 insertions(+), 92 deletions(-) create mode 100644 plugins/adaptername.c diff --git a/Makefile.am b/Makefile.am index 175f8c9..2f3051c 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..987b7e1 100644 --- a/configure.ac +++ b/configure.ac @@ -35,6 +35,10 @@ 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_MSG_ERROR(inotify headers are required and missing)]) 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..56a74c9 --- /dev/null +++ b/plugins/adaptername.c @@ -0,0 +1,279 @@ +/* + * + * 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" + +#include <sys/inotify.h> +#define EVENT_SIZE (sizeof (struct inotify_event)) +#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16)) + +#define MACHINE_INFO_DIR "/etc/" +#define MACHINE_INFO_FILE "machine-info" + +static GIOChannel *inotify = NULL; +static int watch_fd = -1; + +/* 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) { + if (current_id != 0) { + 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) +{ + if (watch_fd >= 0) + close (watch_fd); + if (inotify != NULL) + g_io_channel_shutdown(inotify, FALSE, NULL); +} + +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); + + 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; + } + + 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 c30febc..5598d17 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -182,64 +182,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) { @@ -912,10 +854,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); @@ -934,38 +876,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); } @@ -2577,14 +2510,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 3526849..13971bf 100644 --- a/src/adapter.h +++ b/src/adapter.h @@ -115,7 +115,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, -- 1.7.5.1