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
34 connman_task_notify_t func;
43 connman_task_exit_t exit_func;
48 static GHashTable *task_hash = NULL;
50 static volatile gint task_counter;
52 static DBusConnection *connection;
54 static void free_pointer(gpointer data, gpointer user_data)
59 static void free_task(gpointer data)
61 struct connman_task *task = data;
65 g_hash_table_destroy(task->notify);
69 kill(task->pid, SIGTERM);
71 g_ptr_array_foreach(task->envp, free_pointer, NULL);
72 g_ptr_array_free(task->envp, TRUE);
74 g_ptr_array_foreach(task->argv, free_pointer, NULL);
75 g_ptr_array_free(task->argv, TRUE);
82 * connman_task_create:
83 * @program: name of executable
85 * Allocate a new task of given #program
87 * Returns: a newly-allocated #connman_task structure
89 struct connman_task *connman_task_create(const char *program)
91 struct connman_task *task;
97 task = g_try_new0(struct connman_task, 1);
101 counter = g_atomic_int_exchange_and_add(&task_counter, 1);
103 task->path = g_strdup_printf("/task/%d", counter);
106 task->argv = g_ptr_array_new();
107 task->envp = g_ptr_array_new();
109 str = g_strdup(program);
110 g_ptr_array_add(task->argv, str);
112 task->notify = g_hash_table_new_full(g_str_hash, g_str_equal,
115 DBG("task %p", task);
117 g_hash_table_insert(task_hash, task->path, task);
123 * connman_task_destory:
124 * @task: task structure
126 * Remove and destory #task
128 void connman_task_destroy(struct connman_task *task)
130 DBG("task %p", task);
132 g_hash_table_remove(task_hash, task->path);
136 * connman_task_add_argument:
137 * @task: task structure
138 * @argument: argument name
139 * @value: optional argument value
141 * Add a new command line argument
143 int connman_task_add_argument(struct connman_task *task,
144 const char *argument, const char *value)
148 DBG("task %p arg %s val %s", task, argument, value);
150 if (argument == NULL)
153 str = g_strdup(argument);
154 g_ptr_array_add(task->argv, str);
157 str = g_strdup(value);
158 g_ptr_array_add(task->argv, str);
165 * connman_task_add_variable:
166 * @task: task structure
167 * @key: variable name
168 * @value: optional variable value
170 * Add a new environment variable
172 int connman_task_add_variable(struct connman_task *task,
173 const char *key, const char *value)
177 DBG("task %p key %s val %s", task, key, value);
182 str = g_strdup_printf("%s=%s", key, value ? value : "");
183 g_ptr_array_add(task->envp, str);
189 * connman_task_set_notify:
190 * @task: task structure
191 * @member: notifcation method name
192 * @function: notification callback
193 * @user_data: optional notification user data
195 * Set notification handler for #member
197 int connman_task_set_notify(struct connman_task *task, const char *member,
198 connman_task_notify_t function, void *user_data)
200 struct notify_data *notify;
202 DBG("task %p", task);
204 notify = g_try_new0(struct notify_data, 1);
208 notify->func = function;
209 notify->data = user_data;
211 g_hash_table_insert(task->notify, g_strdup(member), notify);
216 static void task_died(GPid pid, gint status, gpointer user_data)
218 struct connman_task *task = user_data;
220 if (WIFEXITED(status))
221 DBG("task %p exit status %d", task, WEXITSTATUS(status));
223 DBG("task %p signal %d", task, WTERMSIG(status));
225 g_spawn_close_pid(pid);
229 task->exit_func(task, task->exit_data);
232 static void task_setup(gpointer user_data)
234 struct connman_task *task = user_data;
236 DBG("task %p", task);
241 * @task: task structure
242 * @function: exit callback
243 * @user_data: optional exit user data
245 * Execute program specified by #task
247 int connman_task_run(struct connman_task *task,
248 connman_task_exit_t function, void *user_data)
250 GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD |
251 G_SPAWN_STDOUT_TO_DEV_NULL;
254 DBG("task %p", task);
259 task->exit_func = function;
260 task->exit_data = user_data;
262 if (g_ptr_array_index(task->argv, task->argv->len - 1) != NULL)
263 g_ptr_array_add(task->argv, NULL);
265 if (task->envp->len == 0 || g_ptr_array_index(task->envp,
266 task->envp->len - 1) != NULL) {
267 if (g_hash_table_size(task->notify) > 0) {
271 busname = dbus_bus_get_unique_name(connection);
272 str = g_strdup_printf("CONNMAN_BUSNAME=%s", busname);
273 g_ptr_array_add(task->envp, str);
275 str = g_strdup_printf("CONNMAN_INTERFACE=%s",
276 CONNMAN_TASK_INTERFACE);
277 g_ptr_array_add(task->envp, str);
279 str = g_strdup_printf("CONNMAN_PATH=%s", task->path);
280 g_ptr_array_add(task->envp, str);
283 g_ptr_array_add(task->envp, NULL);
286 argv = (char **) task->argv->pdata;
287 envp = (char **) task->envp->pdata;
289 if (g_spawn_async(NULL, argv, envp, flags,
290 task_setup, task, &task->pid, NULL) == FALSE) {
291 connman_error("Failed to spawn %s", argv[0]);
295 g_child_watch_add(task->pid, task_died, task);
302 * @task: task structure
304 * Stop program specified by #task
306 int connman_task_stop(struct connman_task *task)
308 DBG("task %p", task);
311 kill(task->pid, SIGTERM);
316 static DBusHandlerResult task_filter(DBusConnection *connection,
317 DBusMessage *message, void *user_data)
319 struct connman_task *task;
320 struct notify_data *notify;
321 const char *path, *member;
323 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
324 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
326 if (dbus_message_has_interface(message,
327 CONNMAN_TASK_INTERFACE) == FALSE)
328 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
330 path = dbus_message_get_path(message);
332 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
334 task = g_hash_table_lookup(task_hash, path);
336 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
338 if (dbus_message_get_no_reply(message) == FALSE) {
342 reply = dbus_message_new_method_return(message);
344 return DBUS_HANDLER_RESULT_NEED_MEMORY;
346 result = dbus_connection_send(connection, reply, NULL);
348 dbus_message_unref(reply);
351 member = dbus_message_get_member(message);
353 return DBUS_HANDLER_RESULT_HANDLED;
355 notify = g_hash_table_lookup(task->notify, member);
357 return DBUS_HANDLER_RESULT_HANDLED;
360 notify->func(task, message, notify->data);
362 return DBUS_HANDLER_RESULT_HANDLED;
365 static const char *task_rule = "type=method_call"
366 ",interface=" CONNMAN_TASK_INTERFACE;
368 int __connman_task_init(void)
372 connection = connman_dbus_get_connection();
374 dbus_connection_add_filter(connection, task_filter, NULL, NULL);
376 g_atomic_int_set(&task_counter, 0);
378 task_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
381 dbus_bus_add_match(connection, task_rule, NULL);
382 dbus_connection_flush(connection);
387 void __connman_task_cleanup(void)
391 dbus_bus_remove_match(connection, task_rule, NULL);
392 dbus_connection_flush(connection);
394 g_hash_table_destroy(task_hash);
397 dbus_connection_remove_filter(connection, task_filter, NULL);
399 dbus_connection_unref(connection);