5
* Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License version 2 as
9
* published by the Free Software Foundation.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35
connman_task_notify_t func;
44
connman_task_exit_t exit_func;
49
static GHashTable *task_hash = NULL;
51
static volatile gint task_counter;
53
static DBusConnection *connection;
55
static void free_pointer(gpointer data, gpointer user_data)
60
static void free_task(gpointer data)
62
struct connman_task *task = data;
66
g_hash_table_destroy(task->notify);
70
kill(task->pid, SIGTERM);
72
g_ptr_array_foreach(task->envp, free_pointer, NULL);
73
g_ptr_array_free(task->envp, TRUE);
75
g_ptr_array_foreach(task->argv, free_pointer, NULL);
76
g_ptr_array_free(task->argv, TRUE);
83
* connman_task_create:
84
* @program: name of executable
86
* Allocate a new task of given #program
88
* Returns: a newly-allocated #connman_task structure
90
struct connman_task *connman_task_create(const char *program)
92
struct connman_task *task;
98
task = g_try_new0(struct connman_task, 1);
102
counter = g_atomic_int_exchange_and_add(&task_counter, 1);
104
task->path = g_strdup_printf("/task/%d", counter);
107
task->argv = g_ptr_array_new();
108
task->envp = g_ptr_array_new();
110
str = g_strdup(program);
111
g_ptr_array_add(task->argv, str);
113
task->notify = g_hash_table_new_full(g_str_hash, g_str_equal,
116
DBG("task %p", task);
118
g_hash_table_insert(task_hash, task->path, task);
124
* connman_task_destory:
125
* @task: task structure
127
* Remove and destory #task
129
void connman_task_destroy(struct connman_task *task)
131
DBG("task %p", task);
133
g_hash_table_remove(task_hash, task->path);
137
* connman_task_get_path:
138
* @task: task structure
142
const char *connman_task_get_path(struct connman_task *task)
148
* connman_task_add_argument:
149
* @task: task structure
150
* @name: argument name
151
* @format: format string
152
* @Varargs: list of arguments
154
* Add a new command line argument
156
int connman_task_add_argument(struct connman_task *task,
157
const char *name, const char *format, ...)
162
DBG("task %p arg %s", task, name);
167
str = g_strdup(name);
168
g_ptr_array_add(task->argv, str);
170
va_start(ap, format);
172
if (format != NULL) {
173
str = g_strdup_vprintf(format, ap);
174
g_ptr_array_add(task->argv, str);
183
* connman_task_add_variable:
184
* @task: task structure
185
* @key: variable name
186
* @format: format string
187
* @Varargs: list of arguments
189
* Add a new environment variable
191
int connman_task_add_variable(struct connman_task *task,
192
const char *key, const char *format, ...)
197
DBG("task %p key %s", task, key);
202
va_start(ap, format);
204
val = g_strdup_vprintf(format, ap);
205
str = g_strdup_printf("%s=%s", key, format ? format : "");
206
g_ptr_array_add(task->envp, str);
215
* connman_task_set_notify:
216
* @task: task structure
217
* @member: notifcation method name
218
* @function: notification callback
219
* @user_data: optional notification user data
221
* Set notification handler for #member
223
int connman_task_set_notify(struct connman_task *task, const char *member,
224
connman_task_notify_t function, void *user_data)
226
struct notify_data *notify;
228
DBG("task %p", task);
230
notify = g_try_new0(struct notify_data, 1);
234
notify->func = function;
235
notify->data = user_data;
237
g_hash_table_insert(task->notify, g_strdup(member), notify);
242
static void task_died(GPid pid, gint status, gpointer user_data)
244
struct connman_task *task = user_data;
246
if (WIFEXITED(status))
247
DBG("task %p exit status %d", task, WEXITSTATUS(status));
249
DBG("task %p signal %d", task, WTERMSIG(status));
251
g_spawn_close_pid(pid);
255
task->exit_func(task, task->exit_data);
258
static void task_setup(gpointer user_data)
260
struct connman_task *task = user_data;
262
DBG("task %p", task);
267
* @task: task structure
268
* @function: exit callback
269
* @user_data: optional exit user data
271
* Execute program specified by #task
273
int connman_task_run(struct connman_task *task,
274
connman_task_exit_t function, void *user_data)
276
GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD |
277
G_SPAWN_STDOUT_TO_DEV_NULL;
280
DBG("task %p", task);
285
task->exit_func = function;
286
task->exit_data = user_data;
288
if (g_ptr_array_index(task->argv, task->argv->len - 1) != NULL)
289
g_ptr_array_add(task->argv, NULL);
291
if (task->envp->len == 0 || g_ptr_array_index(task->envp,
292
task->envp->len - 1) != NULL) {
293
if (g_hash_table_size(task->notify) > 0) {
297
busname = dbus_bus_get_unique_name(connection);
298
str = g_strdup_printf("CONNMAN_BUSNAME=%s", busname);
299
g_ptr_array_add(task->envp, str);
301
str = g_strdup_printf("CONNMAN_INTERFACE=%s",
302
CONNMAN_TASK_INTERFACE);
303
g_ptr_array_add(task->envp, str);
305
str = g_strdup_printf("CONNMAN_PATH=%s", task->path);
306
g_ptr_array_add(task->envp, str);
309
g_ptr_array_add(task->envp, NULL);
312
argv = (char **) task->argv->pdata;
313
envp = (char **) task->envp->pdata;
315
if (g_spawn_async(NULL, argv, envp, flags,
316
task_setup, task, &task->pid, NULL) == FALSE) {
317
connman_error("Failed to spawn %s", argv[0]);
321
g_child_watch_add(task->pid, task_died, task);
328
* @task: task structure
330
* Stop program specified by #task
332
int connman_task_stop(struct connman_task *task)
334
DBG("task %p", task);
337
kill(task->pid, SIGTERM);
342
static DBusHandlerResult task_filter(DBusConnection *connection,
343
DBusMessage *message, void *user_data)
345
struct connman_task *task;
346
struct notify_data *notify;
347
const char *path, *member;
349
if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
350
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
352
if (dbus_message_has_interface(message,
353
CONNMAN_TASK_INTERFACE) == FALSE)
354
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
356
path = dbus_message_get_path(message);
358
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
360
task = g_hash_table_lookup(task_hash, path);
362
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
364
if (dbus_message_get_no_reply(message) == FALSE) {
368
reply = dbus_message_new_method_return(message);
370
return DBUS_HANDLER_RESULT_NEED_MEMORY;
372
result = dbus_connection_send(connection, reply, NULL);
374
dbus_message_unref(reply);
377
member = dbus_message_get_member(message);
379
return DBUS_HANDLER_RESULT_HANDLED;
381
notify = g_hash_table_lookup(task->notify, member);
383
return DBUS_HANDLER_RESULT_HANDLED;
386
notify->func(task, message, notify->data);
388
return DBUS_HANDLER_RESULT_HANDLED;
391
static const char *task_rule = "type=method_call"
392
",interface=" CONNMAN_TASK_INTERFACE;
394
int __connman_task_init(void)
398
connection = connman_dbus_get_connection();
400
dbus_connection_add_filter(connection, task_filter, NULL, NULL);
402
g_atomic_int_set(&task_counter, 0);
404
task_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
407
dbus_bus_add_match(connection, task_rule, NULL);
408
dbus_connection_flush(connection);
413
void __connman_task_cleanup(void)
417
dbus_bus_remove_match(connection, task_rule, NULL);
418
dbus_connection_flush(connection);
420
g_hash_table_destroy(task_hash);
423
dbus_connection_remove_filter(connection, task_filter, NULL);
425
dbus_connection_unref(connection);