Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / obexd / src / main.c
1 /*
2  *
3  *  OBEX Server
4  *
5  *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
6  *
7  *
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.
12  *
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.
17  *
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
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <stdint.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/wait.h>
38 #include <sys/signalfd.h>
39 #include <fcntl.h>
40 #include <termios.h>
41 #include <getopt.h>
42 #include <syslog.h>
43 #include <glib.h>
44
45 #include "gdbus/gdbus.h"
46
47 #include "../client/manager.h"
48
49 #include "log.h"
50 #include "obexd.h"
51 #include "server.h"
52
53 #define DEFAULT_CAP_FILE CONFIGDIR "/capability.xml"
54
55 static GMainLoop *main_loop = NULL;
56
57 static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
58                                                         gpointer user_data)
59 {
60         static unsigned int __terminated = 0;
61         struct signalfd_siginfo si;
62         ssize_t result;
63         int fd;
64
65         if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
66                 return FALSE;
67
68         fd = g_io_channel_unix_get_fd(channel);
69
70         result = read(fd, &si, sizeof(si));
71         if (result != sizeof(si))
72                 return FALSE;
73
74         switch (si.ssi_signo) {
75         case SIGINT:
76         case SIGTERM:
77                 if (__terminated == 0) {
78                         info("Terminating");
79                         g_main_loop_quit(main_loop);
80                 }
81
82                 __terminated = 1;
83                 break;
84         case SIGUSR2:
85                 __obex_log_enable_debug();
86                 break;
87         }
88
89         return TRUE;
90 }
91
92 static guint setup_signalfd(void)
93 {
94         GIOChannel *channel;
95         guint source;
96         sigset_t mask;
97         int fd;
98
99         sigemptyset(&mask);
100         sigaddset(&mask, SIGINT);
101         sigaddset(&mask, SIGTERM);
102         sigaddset(&mask, SIGUSR2);
103
104         if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
105                 perror("Failed to set signal mask");
106                 return 0;
107         }
108
109         fd = signalfd(-1, &mask, 0);
110         if (fd < 0) {
111                 perror("Failed to create signal descriptor");
112                 return 0;
113         }
114
115         channel = g_io_channel_unix_new(fd);
116
117         g_io_channel_set_close_on_unref(channel, TRUE);
118         g_io_channel_set_encoding(channel, NULL, NULL);
119         g_io_channel_set_buffered(channel, FALSE);
120
121         source = g_io_add_watch(channel,
122                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
123                                 signal_handler, NULL);
124
125         g_io_channel_unref(channel);
126
127         return source;
128 }
129
130 static gboolean option_detach = TRUE;
131 static char *option_debug = NULL;
132
133 static char *option_root = NULL;
134 static char *option_root_setup = NULL;
135 static char *option_capability = NULL;
136 static char *option_plugin = NULL;
137 static char *option_noplugin = NULL;
138
139 static gboolean option_autoaccept = FALSE;
140 static gboolean option_symlinks = FALSE;
141
142 static gboolean parse_debug(const char *key, const char *value,
143                                 gpointer user_data, GError **error)
144 {
145         if (value)
146                 option_debug = g_strdup(value);
147         else
148                 option_debug = g_strdup("*");
149
150         return TRUE;
151 }
152
153 static GOptionEntry options[] = {
154         { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
155                                 G_OPTION_ARG_CALLBACK, parse_debug,
156                                 "Enable debug information output", "DEBUG" },
157         { "plugin", 'p', 0, G_OPTION_ARG_STRING, &option_plugin,
158                                 "Specify plugins to load", "NAME,..." },
159         { "noplugin", 'P', 0, G_OPTION_ARG_STRING, &option_noplugin,
160                                 "Specify plugins not to load", "NAME,..." },
161         { "nodetach", 'n', G_OPTION_FLAG_REVERSE,
162                                 G_OPTION_ARG_NONE, &option_detach,
163                                 "Run with logging in foreground" },
164         { "root", 'r', 0, G_OPTION_ARG_STRING, &option_root,
165                                 "Specify root folder location. Both absolute "
166                                 "and relative can be used, but relative paths "
167                                 "are assumed to be relative to user $HOME "
168                                 "folder. Default $XDG_CACHE_HOME", "PATH" },
169         { "root-setup", 'S', 0, G_OPTION_ARG_STRING, &option_root_setup,
170                                 "Root folder setup script", "SCRIPT" },
171         { "symlinks", 'l', 0, G_OPTION_ARG_NONE, &option_symlinks,
172                                 "Allow symlinks leading outside of the root "
173                                 "folder" },
174         { "capability", 'c', 0, G_OPTION_ARG_STRING, &option_capability,
175                                 "Specify capability file, use '!' mark for "
176                                 "scripts", "FILE" },
177         { "auto-accept", 'a', 0, G_OPTION_ARG_NONE, &option_autoaccept,
178                                 "Automatically accept push requests" },
179         { NULL },
180 };
181
182 #ifdef __TIZEN_PATCH__
183 void obex_option_set_root_folder(const char *root)
184 {
185         g_free(option_root);
186         option_root = g_strdup(root);
187 }
188 #endif
189
190 gboolean obex_option_auto_accept(void)
191 {
192         return option_autoaccept;
193 }
194
195 const char *obex_option_root_folder(void)
196 {
197         return option_root;
198 }
199
200 gboolean obex_option_symlinks(void)
201 {
202         return option_symlinks;
203 }
204
205 const char *obex_option_capability(void)
206 {
207         return option_capability;
208 }
209
210 static gboolean is_dir(const char *dir)
211 {
212         struct stat st;
213
214         if (stat(dir, &st) < 0) {
215                 error("stat(%s): %s (%d)", dir, strerror(errno), errno);
216                 return FALSE;
217         }
218
219         return S_ISDIR(st.st_mode);
220 }
221
222 static gboolean root_folder_setup(char *root, char *root_setup)
223 {
224         int status;
225         char *argv[3] = { root_setup, root, NULL };
226
227         if (is_dir(root))
228                 return TRUE;
229
230         if (root_setup == NULL)
231                 return FALSE;
232
233         DBG("Setting up %s using %s", root, root_setup);
234
235         if (!g_spawn_sync(NULL, argv, NULL, 0, NULL, NULL, NULL, NULL,
236                                                         &status, NULL)) {
237                 error("Unable to execute %s", root_setup);
238                 return FALSE;
239         }
240
241         if (WEXITSTATUS(status) != EXIT_SUCCESS) {
242                 error("%s exited with status %d", root_setup,
243                                                         WEXITSTATUS(status));
244                 return FALSE;
245         }
246
247         return is_dir(root);
248 }
249
250 int main(int argc, char *argv[])
251 {
252         GOptionContext *context;
253         GError *err = NULL;
254         guint signal;
255
256 #ifdef NEED_THREADS
257         if (g_thread_supported() == FALSE)
258                 g_thread_init(NULL);
259 #endif
260
261         context = g_option_context_new(NULL);
262         g_option_context_add_main_entries(context, options, NULL);
263
264         if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
265                 if (err != NULL) {
266                         g_printerr("%s\n", err->message);
267                         g_error_free(err);
268                 } else
269                         g_printerr("An unknown error occurred\n");
270                 exit(EXIT_FAILURE);
271         }
272
273         g_option_context_free(context);
274
275         __obex_log_init(option_debug, option_detach);
276
277         DBG("Entering main loop");
278
279         main_loop = g_main_loop_new(NULL, FALSE);
280
281         signal = setup_signalfd();
282
283 #ifdef NEED_THREADS
284         if (dbus_threads_init_default() == FALSE) {
285                 fprintf(stderr, "Can't init usage of threads\n");
286                 exit(EXIT_FAILURE);
287         }
288 #endif
289
290         if (manager_init() == FALSE) {
291                 error("manager_init failed");
292                 exit(EXIT_FAILURE);
293         }
294
295         if (option_root == NULL) {
296                 option_root = g_build_filename(g_get_user_cache_dir(), "obexd",
297                                                                         NULL);
298                 g_mkdir_with_parents(option_root, 0700);
299         }
300
301         if (option_root[0] != '/') {
302                 const char *home = getenv("HOME");
303                 if (home) {
304                         char *old_root = option_root;
305                         option_root = g_strdup_printf("%s/%s", home, old_root);
306                         g_free(old_root);
307                 }
308         }
309
310         if (option_capability == NULL)
311                 option_capability = g_strdup(DEFAULT_CAP_FILE);
312
313         plugin_init(option_plugin, option_noplugin);
314
315         if (obex_server_init() < 0) {
316                 error("obex_server_init failed");
317                 exit(EXIT_FAILURE);
318         }
319
320         if (!root_folder_setup(option_root, option_root_setup)) {
321                 error("Unable to setup root folder %s", option_root);
322                 exit(EXIT_FAILURE);
323         }
324
325         if (client_manager_init() < 0) {
326                 error("client_manager_init failed");
327                 exit(EXIT_FAILURE);
328         }
329
330         g_main_loop_run(main_loop);
331
332         g_source_remove(signal);
333
334         client_manager_exit();
335
336         obex_server_exit();
337
338         plugin_cleanup();
339
340         manager_cleanup();
341
342         g_main_loop_unref(main_loop);
343
344         g_free(option_capability);
345         g_free(option_root);
346
347         __obex_log_cleanup();
348
349         return 0;
350 }