3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2011 Red Hat, Inc.
6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 * Author: Bastien Nocera <hadess@hadess.net>
24 * Marcel Holtmann <marcel@holtmann.org> (for expand_name)
37 #include <bluetooth/bluetooth.h>
40 #include "hcid.h" /* For main_opts */
43 #include "device.h" /* Needed for storage.h */
47 #include <sys/inotify.h>
48 #define EVENT_SIZE (sizeof (struct inotify_event))
49 #define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
51 #define MACHINE_INFO_DIR "/etc/"
52 #define MACHINE_INFO_FILE "machine-info"
54 static GIOChannel *inotify = NULL;
55 static int watch_d = -1;
57 /* This file is part of systemd's hostnamed functionality:
58 * http://0pointer.de/public/systemd-man/machine-info.html
59 * http://www.freedesktop.org/wiki/Software/systemd/hostnamed
61 static char *read_pretty_host_name(void)
67 if (g_file_get_contents(MACHINE_INFO_DIR MACHINE_INFO_FILE,
68 &contents, NULL, NULL) == FALSE)
71 lines = g_strsplit_set(contents, "\r\n", 0);
78 for (i = 0; lines[i] != NULL; i++) {
79 if (g_str_has_prefix(lines[i], "PRETTY_HOSTNAME=")) {
80 ret = g_strdup(lines[i] + strlen("PRETTY_HOSTNAME="));
91 * Device name expansion
95 static char *expand_name(char *dst, int size, char *str, int dev_id)
97 register int sp, np, olen;
104 while (np < size - 1 && str[sp]) {
111 sprintf(buf, "%d", dev_id);
116 opt = main_opts.host_name;
120 dst[np++] = str[sp++];
130 if (np + olen < size - 1)
131 memcpy(dst + np, opt, olen);
141 dst[np++] = str[sp++];
149 static int get_default_adapter_id(void)
151 struct btd_adapter *default_adapter;
153 default_adapter = manager_get_default_adapter();
154 if (default_adapter == NULL)
157 return adapter_get_dev_id(default_adapter);
160 static void set_pretty_name(struct btd_adapter *adapter,
161 const char *pretty_hostname)
166 default_adapter = get_default_adapter_id();
167 current_id = adapter_get_dev_id(adapter);
169 /* Allow us to change the name */
170 adapter_set_allow_name_changes(adapter, TRUE);
172 /* If it's the first device, let's assume it will be the
173 * default one, as we're not told when the default adapter
175 if (default_adapter < 0)
176 default_adapter = current_id;
178 if (default_adapter != current_id) {
181 /* +1 because we don't want an adapter called "Foobar's
183 str = g_strdup_printf("%s #%d", pretty_hostname,
185 DBG("Setting name '%s' for device 'hci%d'", str, current_id);
187 adapter_set_name(adapter, str);
190 DBG("Setting name '%s' for device 'hci%d'", pretty_hostname,
192 adapter_set_name(adapter, pretty_hostname);
195 /* And disable the name change now */
196 adapter_set_allow_name_changes(adapter, FALSE);
199 static int adaptername_probe(struct btd_adapter *adapter)
202 char name[MAX_NAME_LENGTH + 1];
203 char *pretty_hostname;
206 pretty_hostname = read_pretty_host_name();
207 if (pretty_hostname != NULL) {
208 set_pretty_name(adapter, pretty_hostname);
209 g_free(pretty_hostname);
213 adapter_set_allow_name_changes(adapter, TRUE);
214 adapter_get_address(adapter, &bdaddr);
215 current_id = adapter_get_dev_id(adapter);
217 if (read_local_name(&bdaddr, name) < 0)
218 expand_name(name, MAX_NAME_LENGTH, main_opts.name, current_id);
220 DBG("Setting name '%s' for device 'hci%d'", name, current_id);
221 adapter_set_name(adapter, name);
226 static gboolean handle_inotify_cb(GIOChannel *channel, GIOCondition cond,
229 char buf[EVENT_BUF_LEN];
236 err = g_io_channel_read_chars(channel, buf, EVENT_BUF_LEN, &len, NULL);
237 if (err != G_IO_STATUS_NORMAL) {
238 error("Error reading inotify event: %d\n", err);
244 struct inotify_event *pevent = (struct inotify_event *) &buf[i];
246 /* check that it's ours */
247 if (pevent->len && pevent->name != NULL &&
248 strcmp(pevent->name, MACHINE_INFO_FILE) == 0)
251 i += EVENT_SIZE + pevent->len;
254 if (changed != FALSE) {
255 DBG(MACHINE_INFO_DIR MACHINE_INFO_FILE
256 " changed, changing names for adapters");
257 manager_foreach_adapter((adapter_cb) adaptername_probe, NULL);
263 static void adaptername_remove(struct btd_adapter *adapter)
267 static struct btd_adapter_driver adaptername_driver = {
268 .name = "adaptername",
269 .probe = adaptername_probe,
270 .remove = adaptername_remove,
273 static int adaptername_init(void)
279 err = btd_register_adapter_driver(&adaptername_driver);
283 inot_fd = inotify_init();
285 error("Failed to setup inotify");
289 mask = IN_CLOSE_WRITE;
292 mask |= IN_MOVED_FROM;
295 watch_d = inotify_add_watch(inot_fd, MACHINE_INFO_DIR, mask);
297 error("Failed to setup watch for '%s'", MACHINE_INFO_DIR);
302 inotify = g_io_channel_unix_new(inot_fd);
303 g_io_channel_set_close_on_unref(inotify, TRUE);
304 g_io_channel_set_encoding(inotify, NULL, NULL);
305 g_io_channel_set_flags(inotify, G_IO_FLAG_NONBLOCK, NULL);
306 g_io_add_watch(inotify, G_IO_IN, handle_inotify_cb, NULL);
311 static void adaptername_exit(void)
313 if (watch_d >= 0 && inotify != NULL) {
314 int inot_fd = g_io_channel_unix_get_fd(inotify);
315 inotify_rm_watch(inot_fd, watch_d);
318 if (inotify != NULL) {
319 g_io_channel_shutdown(inotify, FALSE, NULL);
320 g_io_channel_unref(inotify);
323 btd_unregister_adapter_driver(&adaptername_driver);
326 BLUETOOTH_PLUGIN_DEFINE(adaptername, VERSION,
327 BLUETOOTH_PLUGIN_PRIORITY_LOW, adaptername_init, adaptername_exit)