diff --git a/daemon/app_supervisor.c b/daemon/app_supervisor.c index 7b5480b0..cb024e9e 100644 --- a/daemon/app_supervisor.c +++ b/daemon/app_supervisor.c @@ -24,7 +24,6 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #include #include @@ -106,23 +105,6 @@ ladish_app_supervisor_create( return true; } -struct ladish_app * ladish_app_supervisor_find_app_by_name(struct ladish_app_supervisor * supervisor_ptr, const char * name) -{ - struct list_head * node_ptr; - struct ladish_app * app_ptr; - - list_for_each(node_ptr, &supervisor_ptr->applist) - { - app_ptr = list_entry(node_ptr, struct ladish_app, siblings); - if (strcmp(app_ptr->name, name) == 0) - { - return app_ptr; - } - } - - return NULL; -} - struct ladish_app * ladish_app_supervisor_find_app_by_id(struct ladish_app_supervisor * supervisor_ptr, uint64_t id) { struct list_head * node_ptr; @@ -140,70 +122,6 @@ struct ladish_app * ladish_app_supervisor_find_app_by_id(struct ladish_app_super return NULL; } -static -struct ladish_app * -add_app_internal( - struct ladish_app_supervisor * supervisor_ptr, - const char * name, - const char * commandline, - dbus_bool_t terminal, - dbus_bool_t autorun, - uint8_t level) -{ - struct ladish_app * app_ptr; - dbus_bool_t running; - - app_ptr = malloc(sizeof(struct ladish_app)); - if (app_ptr == NULL) - { - log_error("malloc of struct ladish_app failed"); - return NULL; - } - - app_ptr->name = strdup(name); - if (app_ptr->name == NULL) - { - log_error("strdup() failed for app name"); - free(app_ptr); - return NULL; - } - - app_ptr->commandline = strdup(commandline); - if (app_ptr->commandline == NULL) - { - log_error("strdup() failed for app commandline"); - free(app_ptr->name); - free(app_ptr); - return NULL; - } - - app_ptr->terminal = terminal; - app_ptr->level = level; - app_ptr->pid = 0; - - app_ptr->id = supervisor_ptr->next_id++; - app_ptr->zombie = false; - app_ptr->hidden = false; - app_ptr->autorun = autorun; - list_add_tail(&app_ptr->siblings, &supervisor_ptr->applist); - - running = false; - dbus_signal_emit( - g_dbus_connection, - supervisor_ptr->opath, - IFACE_APP_SUPERVISOR, - "AppAdded", - "ttsbby", - &supervisor_ptr->version, - &app_ptr->id, - &app_ptr->name, - &running, - &terminal, - &app_ptr->level); - - return app_ptr; -} - void remove_app_internal(struct ladish_app_supervisor * supervisor_ptr, struct ladish_app * app_ptr) { list_del(&app_ptr->siblings); @@ -253,6 +171,91 @@ void emit_app_state_changed(struct ladish_app_supervisor * supervisor_ptr, struc #define supervisor_ptr ((struct ladish_app_supervisor *)supervisor_handle) +const char * ladish_app_supervisor_get_opath(ladish_app_supervisor_handle supervisor_handle) +{ + return supervisor_ptr->opath; +} + +ladish_app_handle ladish_app_supervisor_find_app_by_name(ladish_app_supervisor_handle supervisor_handle, const char * name) +{ + struct list_head * node_ptr; + struct ladish_app * app_ptr; + + list_for_each(node_ptr, &supervisor_ptr->applist) + { + app_ptr = list_entry(node_ptr, struct ladish_app, siblings); + if (strcmp(app_ptr->name, name) == 0) + { + return (ladish_app_handle)app_ptr; + } + } + + return NULL; +} + +ladish_app_handle +ladish_app_supervisor_add( + ladish_app_supervisor_handle supervisor_handle, + const char * name, + bool autorun, + const char * command, + bool terminal, + uint8_t level) +{ + struct ladish_app * app_ptr; + dbus_bool_t running; + + app_ptr = malloc(sizeof(struct ladish_app)); + if (app_ptr == NULL) + { + log_error("malloc of struct ladish_app failed"); + return NULL; + } + + app_ptr->name = strdup(name); + if (app_ptr->name == NULL) + { + log_error("strdup() failed for app name"); + free(app_ptr); + return NULL; + } + + app_ptr->commandline = strdup(command); + if (app_ptr->commandline == NULL) + { + log_error("strdup() failed for app commandline"); + free(app_ptr->name); + free(app_ptr); + return NULL; + } + + app_ptr->terminal = terminal; + app_ptr->level = level; + app_ptr->pid = 0; + + app_ptr->id = supervisor_ptr->next_id++; + app_ptr->zombie = false; + app_ptr->hidden = false; + app_ptr->autorun = autorun; + list_add_tail(&app_ptr->siblings, &supervisor_ptr->applist); + + running = false; + dbus_signal_emit( + g_dbus_connection, + supervisor_ptr->opath, + IFACE_APP_SUPERVISOR, + "AppAdded", + "ttsbby", + &supervisor_ptr->version, + &app_ptr->id, + &app_ptr->name, + &running, + &terminal, + &app_ptr->level); + + return (ladish_app_handle)app_ptr; +} + void ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle) { struct list_head * node_ptr; @@ -340,27 +343,26 @@ ladish_app_supervisor_enum( return true; } -bool -ladish_app_supervisor_add( - ladish_app_supervisor_handle supervisor_handle, - const char * name, - bool autorun, - const char * command, - bool terminal, - uint8_t level) -{ - struct ladish_app * app_ptr; +#define app_ptr ((struct ladish_app *)app_handle) - app_ptr = add_app_internal(supervisor_ptr, name, command, terminal, autorun, level); - if (app_ptr == NULL) +bool ladish_app_supervisor_run(ladish_app_supervisor_handle supervisor_handle, ladish_app_handle app_handle) +{ + if (!loader_execute(supervisor_ptr->name, app_ptr->name, "/", app_ptr->terminal, app_ptr->commandline, &app_ptr->pid)) { - log_error("add_app_internal() failed"); return false; } + emit_app_state_changed(supervisor_ptr, app_ptr); return true; } +void ladish_app_supervisor_remove(ladish_app_supervisor_handle supervisor_handle, ladish_app_handle app_handle) +{ + remove_app_internal(supervisor_ptr, app_ptr); +} + +#undef app_ptr + void ladish_app_supervisor_autorun(ladish_app_supervisor_handle supervisor_handle) { struct list_head * node_ptr; @@ -379,7 +381,7 @@ void ladish_app_supervisor_autorun(ladish_app_supervisor_handle supervisor_handl log_info("autorun('%s', %s, '%s') called", app_ptr->name, app_ptr->terminal ? "terminal" : "shell", app_ptr->commandline); - if (!loader_execute(supervisor_ptr->name, app_ptr->name, "/", app_ptr->terminal, app_ptr->commandline, &app_ptr->pid)) + if (!ladish_app_supervisor_run((ladish_app_supervisor_handle)supervisor_ptr, (ladish_app_handle)app_ptr)) { log_error("Execution of '%s' failed", app_ptr->commandline); return; @@ -554,21 +556,15 @@ static void run_custom(struct dbus_method_call * call_ptr) { dbus_bool_t terminal; const char * commandline; - const char * name_param; + const char * name; uint8_t level; - char * name; - char * name_buffer; - size_t len; - char * end; - unsigned int index; - struct ladish_app * app_ptr; if (!dbus_message_get_args( call_ptr->message, &g_dbus_error, DBUS_TYPE_BOOLEAN, &terminal, DBUS_TYPE_STRING, &commandline, - DBUS_TYPE_STRING, &name_param, + DBUS_TYPE_STRING, &name, DBUS_TYPE_BYTE, &level, DBUS_TYPE_INVALID)) { @@ -577,95 +573,19 @@ static void run_custom(struct dbus_method_call * call_ptr) return; } - log_info("run_custom('%s', %s, '%s', %"PRIu8") called", name_param, terminal ? "terminal" : "shell", commandline, level); + log_info("run_custom('%s', %s, '%s', %"PRIu8") called", name, terminal ? "terminal" : "shell", commandline, level); - if (*name_param) + if (ladish_command_new_app( + call_ptr, + ladish_studio_get_cmd_queue(), + supervisor_ptr->opath, + terminal, + commandline, + name, + level)) { - /* allocate and copy app name */ - len = strlen(name_param); - name_buffer = malloc(len + 100); - if (name_buffer == NULL) - { - lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "malloc of app name failed"); - return; - } - - name = name_buffer; - - strcpy(name, name_param); - - end = name + len; + method_return_new_void(call_ptr); } - else - { - /* allocate app name */ - len = strlen(commandline) + 100; - name_buffer = malloc(len); - if (name_buffer == NULL) - { - lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "malloc of app name failed"); - return; - } - - strcpy(name_buffer, commandline); - - /* use first word as name */ - end = name_buffer; - while (*end) - { - if (isspace(*end)) - { - *end = 0; - break; - } - - end++; - } - - name = strrchr(name_buffer, '/'); - if (name == NULL) - { - name = name_buffer; - } - else - { - name++; - } - } - - /* make the app name unique */ - index = 2; - while (ladish_app_supervisor_find_app_by_name(supervisor_ptr, name) != NULL) - { - sprintf(end, "-%u", index); - index++; - } - - app_ptr = add_app_internal(supervisor_ptr, name, commandline, terminal, true, level); - - free(name_buffer); - - if (app_ptr == NULL) - { - lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "add_app_internal() failed"); - return; - } - - if (studio_is_started()) - { - if (!loader_execute(supervisor_ptr->name, app_ptr->name, "/", terminal, commandline, &app_ptr->pid)) - { - lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Execution of '%s' failed", commandline); - remove_app_internal(supervisor_ptr, app_ptr); - return; - } - - log_info("%s pid is %lu", app_ptr->name, (unsigned long)app_ptr->pid); - - emit_app_state_changed(supervisor_ptr, app_ptr); - } - - method_return_new_void(call_ptr); } static void start_app(struct dbus_method_call * call_ptr) @@ -698,7 +618,7 @@ static void start_app(struct dbus_method_call * call_ptr) } app_ptr->zombie = false; - if (!loader_execute(supervisor_ptr->name, app_ptr->name, "/", app_ptr->terminal, app_ptr->commandline, &app_ptr->pid)) + if (!ladish_app_supervisor_run((ladish_app_supervisor_handle)supervisor_ptr, (ladish_app_handle)app_ptr)) { lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Execution of '%s' failed", app_ptr->commandline); return; diff --git a/daemon/app_supervisor.h b/daemon/app_supervisor.h index 7ea673e3..9154046b 100644 --- a/daemon/app_supervisor.h +++ b/daemon/app_supervisor.h @@ -30,6 +30,7 @@ #include "common.h" typedef struct ladish_app_supervisor_tag { int unused; } * ladish_app_supervisor_handle; +typedef struct ladish_app_tag { int unused; } * ladish_app_handle; bool ladish_app_supervisor_create( @@ -58,7 +59,7 @@ void ladish_app_supervisor_clear( ladish_app_supervisor_handle supervisor_handle); -bool +ladish_app_handle ladish_app_supervisor_add( ladish_app_supervisor_handle supervisor_handle, const char * name, @@ -82,6 +83,10 @@ ladish_app_supervisor_search_app( const char * ladish_app_supervisor_get_name(ladish_app_supervisor_handle supervisor_handle); unsigned int ladish_app_supervisor_get_running_app_count(ladish_app_supervisor_handle supervisor_handle); +ladish_app_handle ladish_app_supervisor_find_app_by_name(ladish_app_supervisor_handle supervisor_handle, const char * name); +const char * ladish_app_supervisor_get_opath(ladish_app_supervisor_handle supervisor_handle); +bool ladish_app_supervisor_run(ladish_app_supervisor_handle supervisor_handle, ladish_app_handle app_handle); +void ladish_app_supervisor_remove(ladish_app_supervisor_handle supervisor_handle, ladish_app_handle app_handle); extern const struct dbus_interface_descriptor g_iface_app_supervisor; diff --git a/daemon/cmd.h b/daemon/cmd.h index 02e2784a..5435348e 100644 --- a/daemon/cmd.h +++ b/daemon/cmd.h @@ -2,7 +2,7 @@ /* * LADI Session Handler (ladish) * - * Copyright (C) 2009 Nedko Arnaudov + * Copyright (C) 2009, 2010 Nedko Arnaudov * ************************************************************************** * This file contains interface to the command queue stuff @@ -70,4 +70,14 @@ bool ladish_command_stop_studio(void * call_ptr, struct ladish_cqueue * queue_pt bool ladish_command_unload_studio(void * call_ptr, struct ladish_cqueue * queue_ptr); bool ladish_command_exit(void * call_ptr, struct ladish_cqueue * queue_ptr); +bool +ladish_command_new_app( + void * call_ptr, + struct ladish_cqueue * queue_ptr, + const char * opath, + bool terminal, + const char * commandline, + const char * name, + uint8_t level); + #endif /* #ifndef CMD_H__28542C9B_7CB8_40F8_BBB6_DCE13CBB1E7F__INCLUDED */ diff --git a/daemon/cmd_load_studio.c b/daemon/cmd_load_studio.c index 5a5e0e51..74d61bfd 100644 --- a/daemon/cmd_load_studio.c +++ b/daemon/cmd_load_studio.c @@ -793,7 +793,7 @@ static void callback_elend(void * data, const char * el) log_info("application '%s' (%s, %s, level %u) with commandline '%s'", context_ptr->str, context_ptr->terminal ? "terminal" : "shell", context_ptr->autorun ? "autorun" : "stopped", (unsigned int)context_ptr->level, context_ptr->data); - if (!ladish_app_supervisor_add(g_studio.app_supervisor, context_ptr->str, context_ptr->autorun, context_ptr->data, context_ptr->terminal, context_ptr->level)) + if (ladish_app_supervisor_add(g_studio.app_supervisor, context_ptr->str, context_ptr->autorun, context_ptr->data, context_ptr->terminal, context_ptr->level) == NULL) { log_error("ladish_app_supervisor_add() failed."); context_ptr->error = XML_TRUE; diff --git a/daemon/cmd_new_app.c b/daemon/cmd_new_app.c new file mode 100644 index 00000000..9c448dd0 --- /dev/null +++ b/daemon/cmd_new_app.c @@ -0,0 +1,230 @@ +/* -*- Mode: C ; c-basic-offset: 2 -*- */ +/* + * LADI Session Handler (ladish) + * + * Copyright (C) 2010 Nedko Arnaudov + * + ************************************************************************** + * This file contains implementation of the "new app" command + ************************************************************************** + * + * LADI Session Handler is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * LADI Session Handler is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LADI Session Handler. If not, see + * or write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include "cmd.h" +#include "studio.h" +#include "../dbus/error.h" + +struct ladish_command_new_app +{ + struct ladish_command command; /* must be the first member */ + char * opath; + bool terminal; + char * commandline; + char * name; + uint8_t level; +}; + +#define cmd_ptr ((struct ladish_command_new_app *)context) + +static bool run(void * context) +{ + char * name; + char * name_buffer; + size_t len; + char * end; + unsigned int index; + ladish_app_supervisor_handle supervisor; + ladish_app_handle app; + + ASSERT(cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING); + + log_info("new_app command. opath='%s', name='%s', %s, commandline='%s', level=%"PRIu8") called", cmd_ptr->opath, cmd_ptr->name, cmd_ptr->terminal ? "terminal" : "shell", cmd_ptr->commandline, cmd_ptr->level); + + supervisor = ladish_studio_find_app_supervisor(cmd_ptr->opath); + if (supervisor == NULL) + { + log_error("cannot find supervisor '%s' to run app '%s'", cmd_ptr->opath, cmd_ptr->name); + return false; + } + + if (*cmd_ptr->name) + { + /* allocate and copy app name */ + len = strlen(cmd_ptr->name); + name_buffer = malloc(len + 100); + if (name_buffer == NULL) + { + log_error("malloc of app name failed"); + return false; + } + + name = name_buffer; + + strcpy(name, cmd_ptr->name); + + end = name + len; + } + else + { + /* allocate app name */ + len = strlen(cmd_ptr->commandline) + 100; + name_buffer = malloc(len); + if (name_buffer == NULL) + { + log_error("malloc of app name failed"); + return false; + } + + strcpy(name_buffer, cmd_ptr->commandline); + + /* use first word as name */ + end = name_buffer; + while (*end) + { + if (isspace(*end)) + { + *end = 0; + break; + } + + end++; + } + + name = strrchr(name_buffer, '/'); + if (name == NULL) + { + name = name_buffer; + } + else + { + name++; + } + } + + /* make the app name unique */ + index = 2; + while (ladish_app_supervisor_find_app_by_name(supervisor, name) != NULL) + { + sprintf(end, "-%u", index); + index++; + } + + app = ladish_app_supervisor_add(supervisor, name, true, cmd_ptr->commandline, cmd_ptr->terminal, cmd_ptr->level); + + free(name_buffer); + + if (app == NULL) + { + log_error("ladish_app_supervisor_add() failed"); + return false; + } + + if (studio_is_started()) + { + if (!ladish_app_supervisor_run(supervisor, app)) + { + log_error("Execution of '%s' failed", cmd_ptr->commandline); + ladish_app_supervisor_remove(supervisor, app); + return false; + } + } + + cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE; + return true; +} + +static void destructor(void * context) +{ + log_info("new_app command destructor"); + free(cmd_ptr->opath); + free(cmd_ptr->commandline); + free(cmd_ptr->name); +} + +#undef cmd_ptr + +bool +ladish_command_new_app( + void * call_ptr, + struct ladish_cqueue * queue_ptr, + const char * opath, + bool terminal, + const char * commandline, + const char * name, + uint8_t level) +{ + struct ladish_command_new_app * cmd_ptr; + char * opath_dup; + char * commandline_dup; + char * name_dup; + + opath_dup = strdup(opath); + if (opath_dup == NULL) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup('%s') failed.", opath_dup); + goto fail; + } + + commandline_dup = strdup(commandline); + if (commandline_dup == NULL) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup('%s') failed.", commandline_dup); + goto fail_free_opath; + } + + name_dup = strdup(name); + if (name_dup == NULL) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup('%s') failed.", name_dup); + goto fail_free_commandline; + } + + cmd_ptr = ladish_command_new(sizeof(struct ladish_command_new_app)); + if (cmd_ptr == NULL) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "ladish_command_new() failed."); + goto fail_free_name; + } + + cmd_ptr->command.run = run; + cmd_ptr->command.destructor = destructor; + cmd_ptr->opath = opath_dup; + cmd_ptr->commandline = commandline_dup; + cmd_ptr->name = name_dup; + cmd_ptr->terminal = terminal; + cmd_ptr->level = level; + + if (!ladish_cqueue_add_command(queue_ptr, &cmd_ptr->command)) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "ladish_cqueue_add_command() failed."); + goto fail_destroy_command; + } + + return true; + +fail_destroy_command: + free(cmd_ptr); +fail_free_name: + free(name_dup); +fail_free_commandline: + free(commandline_dup); +fail_free_opath: + free(opath_dup); +fail: + return false; +} diff --git a/daemon/studio.c b/daemon/studio.c index 5c604023..90c7bafc 100644 --- a/daemon/studio.c +++ b/daemon/studio.c @@ -639,6 +639,39 @@ struct ladish_cqueue * ladish_studio_get_cmd_queue(void) return &g_studio.cmd_queue; } +struct ladish_studio_app_supervisor_match_context +{ + const char * opath; + ladish_app_supervisor_handle supervisor; +}; + +#define iterate_context_ptr ((struct ladish_studio_app_supervisor_match_context *)context) + +static bool ladish_studio_app_supervisor_match(void * context, ladish_graph_handle graph, ladish_app_supervisor_handle app_supervisor) +{ + ASSERT(strcmp(ladish_app_supervisor_get_opath(app_supervisor), ladish_graph_get_opath(graph)) == 0); + if (strcmp(ladish_app_supervisor_get_opath(app_supervisor), iterate_context_ptr->opath) == 0) + { + ASSERT(iterate_context_ptr->supervisor == NULL); + iterate_context_ptr->supervisor = app_supervisor; + return false; /* stop iteration */ + } + + return true; /* continue iteration */ +} + +#undef iterate_context_ptr + +ladish_app_supervisor_handle ladish_studio_find_app_supervisor(const char * opath) +{ + struct ladish_studio_app_supervisor_match_context ctx; + + ctx.opath = opath; + ctx.supervisor = NULL; + studio_iterate_virtual_graphs(&ctx, ladish_studio_app_supervisor_match); + return ctx.supervisor; +} + bool studios_iterate(void * call_ptr, void * context, bool (* callback)(void * call_ptr, void * context, const char * studio, uint32_t modtime)) { DIR * dir; diff --git a/daemon/studio.h b/daemon/studio.h index 1592dbd3..8f934cdf 100644 --- a/daemon/studio.h +++ b/daemon/studio.h @@ -50,6 +50,7 @@ studio_iterate_virtual_graphs( ladish_app_supervisor_handle app_supervisor)); void studio_stop_app_supervisors(void); +ladish_app_supervisor_handle ladish_studio_find_app_supervisor(const char * opath); struct ladish_cqueue * ladish_studio_get_cmd_queue(void); #endif /* #ifndef STUDIO_H__0BEDE85E_4FB3_4D74_BC08_C373A22409C0__INCLUDED */ diff --git a/wscript b/wscript index 8e88422c..0c849e71 100644 --- a/wscript +++ b/wscript @@ -228,6 +228,7 @@ def build(bld): 'cmd_start_studio.c', 'cmd_stop_studio.c', 'cmd_unload_studio.c', + 'cmd_new_app.c', 'cmd_exit.c', 'cqueue.c', 'app_supervisor.c',