Fix the bug : TIVI-204 Fail to connect to bluetooth network
[profile/ivi/bluez.git] / plugins / adaptername.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2011  Red Hat, Inc.
6  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
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.
13  *
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.
18  *
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
22  *
23  *  Author: Bastien Nocera <hadess@hadess.net>
24  *  Marcel Holtmann <marcel@holtmann.org> (for expand_name)
25  *
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <errno.h>
35
36 #include <glib.h>
37 #include <bluetooth/bluetooth.h>
38
39 #include "plugin.h"
40 #include "hcid.h" /* For main_opts */
41 #include "adapter.h"
42 #include "manager.h"
43 #include "device.h" /* Needed for storage.h */
44 #include "storage.h"
45 #include "log.h"
46
47 #include <sys/inotify.h>
48 #define EVENT_SIZE  (sizeof (struct inotify_event))
49 #define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
50
51 #define MACHINE_INFO_DIR "/etc/"
52 #define MACHINE_INFO_FILE "machine-info"
53
54 static GIOChannel *inotify = NULL;
55 static int watch_d = -1;
56
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
60  */
61 static char *read_pretty_host_name(void)
62 {
63         char *contents, *ret;
64         char **lines;
65         guint i;
66
67         if (g_file_get_contents(MACHINE_INFO_DIR MACHINE_INFO_FILE,
68                                         &contents, NULL, NULL) == FALSE)
69                 return NULL;
70
71         lines = g_strsplit_set(contents, "\r\n", 0);
72         g_free(contents);
73
74         if (lines == NULL)
75                 return NULL;
76
77         ret = NULL;
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="));
81                         break;
82                 }
83         }
84
85         g_strfreev(lines);
86
87         return ret;
88 }
89
90 /*
91  * Device name expansion
92  *   %d - device id
93  *   %h - hostname
94  */
95 static char *expand_name(char *dst, int size, char *str, int dev_id)
96 {
97         register int sp, np, olen;
98         char *opt, buf[10];
99
100         if (!str || !dst)
101                 return NULL;
102
103         sp = np = 0;
104         while (np < size - 1 && str[sp]) {
105                 switch (str[sp]) {
106                 case '%':
107                         opt = NULL;
108
109                         switch (str[sp+1]) {
110                         case 'd':
111                                 sprintf(buf, "%d", dev_id);
112                                 opt = buf;
113                                 break;
114
115                         case 'h':
116                                 opt = main_opts.host_name;
117                                 break;
118
119                         case '%':
120                                 dst[np++] = str[sp++];
121                                 /* fall through */
122                         default:
123                                 sp++;
124                                 continue;
125                         }
126
127                         if (opt) {
128                                 /* substitute */
129                                 olen = strlen(opt);
130                                 if (np + olen < size - 1)
131                                         memcpy(dst + np, opt, olen);
132                                 np += olen;
133                         }
134                         sp += 2;
135                         continue;
136
137                 case '\\':
138                         sp++;
139                         /* fall through */
140                 default:
141                         dst[np++] = str[sp++];
142                         break;
143                 }
144         }
145         dst[np] = '\0';
146         return dst;
147 }
148
149 static int get_default_adapter_id(void)
150 {
151         struct btd_adapter *default_adapter;
152
153         default_adapter = manager_get_default_adapter();
154         if (default_adapter == NULL)
155                 return -1;
156
157         return adapter_get_dev_id(default_adapter);
158 }
159
160 static void set_pretty_name(struct btd_adapter *adapter,
161                                                 const char *pretty_hostname)
162 {
163         int current_id;
164         int default_adapter;
165
166         default_adapter = get_default_adapter_id();
167         current_id = adapter_get_dev_id(adapter);
168
169         /* Allow us to change the name */
170         adapter_set_allow_name_changes(adapter, TRUE);
171
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
174          * changes */
175         if (default_adapter < 0)
176                 default_adapter = current_id;
177
178         if (default_adapter != current_id) {
179                 char *str;
180
181                 /* +1 because we don't want an adapter called "Foobar's
182                  * laptop #0" */
183                 str = g_strdup_printf("%s #%d", pretty_hostname,
184                                                         current_id + 1);
185                 DBG("Setting name '%s' for device 'hci%d'", str, current_id);
186
187                 adapter_set_name(adapter, str);
188                 g_free(str);
189         } else {
190                 DBG("Setting name '%s' for device 'hci%d'", pretty_hostname,
191                                                                 current_id);
192                 adapter_set_name(adapter, pretty_hostname);
193         }
194
195         /* And disable the name change now */
196         adapter_set_allow_name_changes(adapter, FALSE);
197 }
198
199 static int adaptername_probe(struct btd_adapter *adapter)
200 {
201         int current_id;
202         char name[MAX_NAME_LENGTH + 1];
203         char *pretty_hostname;
204         bdaddr_t bdaddr;
205
206         pretty_hostname = read_pretty_host_name();
207         if (pretty_hostname != NULL) {
208                 set_pretty_name(adapter, pretty_hostname);
209                 g_free(pretty_hostname);
210                 return 0;
211         }
212
213         adapter_set_allow_name_changes(adapter, TRUE);
214         adapter_get_address(adapter, &bdaddr);
215         current_id = adapter_get_dev_id(adapter);
216
217         if (read_local_name(&bdaddr, name) < 0)
218                 expand_name(name, MAX_NAME_LENGTH, main_opts.name, current_id);
219
220         DBG("Setting name '%s' for device 'hci%d'", name, current_id);
221         adapter_set_name(adapter, name);
222
223         return 0;
224 }
225
226 static gboolean handle_inotify_cb(GIOChannel *channel, GIOCondition cond,
227                                                                 gpointer data)
228 {
229         char buf[EVENT_BUF_LEN];
230         GIOStatus err;
231         gsize len, i;
232         gboolean changed;
233
234         changed = FALSE;
235
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);
239                 return FALSE;
240         }
241
242         i = 0;
243         while (i < len) {
244                 struct inotify_event *pevent = (struct inotify_event *) &buf[i];
245
246                 /* check that it's ours */
247                 if (pevent->len && pevent->name != NULL &&
248                                 strcmp(pevent->name, MACHINE_INFO_FILE) == 0)
249                         changed = TRUE;
250
251                 i += EVENT_SIZE + pevent->len;
252         }
253
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);
258         }
259
260         return TRUE;
261 }
262
263 static void adaptername_remove(struct btd_adapter *adapter)
264 {
265 }
266
267 static struct btd_adapter_driver adaptername_driver = {
268         .name   = "adaptername",
269         .probe  = adaptername_probe,
270         .remove = adaptername_remove,
271 };
272
273 static int adaptername_init(void)
274 {
275         int err;
276         int inot_fd;
277         guint32 mask;
278
279         err = btd_register_adapter_driver(&adaptername_driver);
280         if (err < 0)
281                 return err;
282
283         inot_fd = inotify_init();
284         if (inot_fd < 0) {
285                 error("Failed to setup inotify");
286                 return 0;
287         }
288
289         mask = IN_CLOSE_WRITE;
290         mask |= IN_DELETE;
291         mask |= IN_CREATE;
292         mask |= IN_MOVED_FROM;
293         mask |= IN_MOVED_TO;
294
295         watch_d = inotify_add_watch(inot_fd, MACHINE_INFO_DIR, mask);
296         if (watch_d < 0) {
297                 error("Failed to setup watch for '%s'", MACHINE_INFO_DIR);
298                 close(inot_fd);
299                 return 0;
300         }
301
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);
307
308         return 0;
309 }
310
311 static void adaptername_exit(void)
312 {
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);
316         }
317
318         if (inotify != NULL) {
319                 g_io_channel_shutdown(inotify, FALSE, NULL);
320                 g_io_channel_unref(inotify);
321         }
322
323         btd_unregister_adapter_driver(&adaptername_driver);
324 }
325
326 BLUETOOTH_PLUGIN_DEFINE(adaptername, VERSION,
327                 BLUETOOTH_PLUGIN_PRIORITY_LOW, adaptername_init, adaptername_exit)