ladishd: app list serialization; autolaunch on load

This commit is contained in:
Nedko Arnaudov 2009-12-05 00:42:40 +02:00
parent 89461c363c
commit 0b6ad2626f
6 changed files with 387 additions and 49 deletions

View File

@ -43,6 +43,8 @@ struct ladish_app
uint8_t level;
pid_t pid;
bool zombie;
bool hidden;
bool autorun;
};
struct ladish_app_supervisor
@ -126,18 +128,85 @@ struct ladish_app * ladish_app_supervisor_find_app_by_id(struct ladish_app_super
return NULL;
}
void remove_app_internal(struct ladish_app_supervisor * supervisor_ptr, struct ladish_app * app_ptr)
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)
{
list_del(&app_ptr->siblings);
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,
"AppRemoved",
"tt",
"AppAdded",
"ttsbby",
&supervisor_ptr->version,
&app_ptr->id);
&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);
if (!app_ptr->hidden)
{
dbus_signal_emit(
g_dbus_connection,
supervisor_ptr->opath,
IFACE_APP_SUPERVISOR,
"AppRemoved",
"tt",
&supervisor_ptr->version,
&app_ptr->id);
}
free(app_ptr->name);
free(app_ptr->commandline);
@ -149,6 +218,11 @@ void emit_app_state_changed(struct ladish_app_supervisor * supervisor_ptr, struc
dbus_bool_t running;
dbus_bool_t terminal;
if (app_ptr->hidden)
{
return;
}
running = app_ptr->pid != 0;
terminal = app_ptr->terminal;
@ -167,16 +241,32 @@ void emit_app_state_changed(struct ladish_app_supervisor * supervisor_ptr, struc
#define supervisor_ptr ((struct ladish_app_supervisor *)supervisor_handle)
void ladish_app_supervisor_destroy(ladish_app_supervisor_handle supervisor_handle)
void ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle)
{
struct list_head * node_ptr;
struct list_head * safe_node_ptr;
struct ladish_app * app_ptr;
while (!list_empty(&supervisor_ptr->applist))
list_for_each_safe(node_ptr, safe_node_ptr, &supervisor_ptr->applist)
{
app_ptr = list_entry(supervisor_ptr->applist.next, struct ladish_app, siblings);
remove_app_internal(supervisor_ptr, app_ptr);
app_ptr = list_entry(node_ptr, struct ladish_app, siblings);
if (app_ptr->pid != 0)
{
log_info("terminating '%s'...", app_ptr->name);
app_ptr->zombie = true;
kill(app_ptr->pid, SIGTERM);
}
else
{
log_info("removing '%s'", app_ptr->name);
remove_app_internal(supervisor_ptr, app_ptr);
}
}
}
void ladish_app_supervisor_destroy(ladish_app_supervisor_handle supervisor_handle)
{
ladish_app_supervisor_clear(supervisor_handle);
free(supervisor_ptr->name);
free(supervisor_ptr->opath);
free(supervisor_ptr);
@ -211,6 +301,82 @@ bool ladish_app_supervisor_child_exit(ladish_app_supervisor_handle supervisor_ha
return false;
}
bool
ladish_app_supervisor_enum(
ladish_app_supervisor_handle supervisor_handle,
void * context,
bool (* callback)(void * context, const char * name, bool running, const char * command, bool terminal, uint8_t level))
{
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 (app_ptr->hidden)
{
continue;
}
if (!callback(context, app_ptr->name, app_ptr->pid != 0, app_ptr->commandline, app_ptr->terminal, app_ptr->level))
{
return false;
}
}
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;
app_ptr = add_app_internal(supervisor_ptr, name, command, terminal, autorun, level);
if (app_ptr == NULL)
{
log_error("add_app_internal() failed");
return false;
}
return true;
}
void ladish_app_supervisor_autorun(ladish_app_supervisor_handle supervisor_handle)
{
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 (!app_ptr->autorun)
{
continue;
}
app_ptr->autorun = false;
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))
{
log_error("Execution of '%s' failed", app_ptr->commandline);
return;
}
emit_app_state_changed(supervisor_ptr, app_ptr);
}
}
#undef supervisor_ptr
#define supervisor_ptr ((struct ladish_app_supervisor *)call_ptr->iface_context)
@ -246,6 +412,11 @@ static void get_all(struct dbus_method_call * call_ptr)
{
app_ptr = list_entry(node_ptr, struct ladish_app, siblings);
if (app_ptr->hidden)
{
continue;
}
log_info("app '%s' (%llu)", app_ptr->name, (unsigned long long)app_ptr->id);
if (!dbus_message_iter_open_container (&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter))
@ -311,7 +482,6 @@ static void run_custom(struct dbus_method_call * call_ptr)
char * end;
unsigned int index;
struct ladish_app * app_ptr;
dbus_bool_t running;
if (!dbus_message_get_args(
call_ptr->message,
@ -378,57 +548,25 @@ static void run_custom(struct dbus_method_call * call_ptr)
index++;
}
app_ptr = malloc(sizeof(struct ladish_app));
app_ptr = add_app_internal(supervisor_ptr, name, commandline, terminal, false, 0);
if (app_ptr == NULL)
{
lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "malloc of struct ladish_app failed");
lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "add_app_internal() failed");
free(name);
return;
}
app_ptr->id = supervisor_ptr->next_id++;
app_ptr->name = name;
app_ptr->commandline = strdup(commandline);
app_ptr->terminal = terminal;
app_ptr->pid = 0;
if (app_ptr->commandline == NULL)
{
lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup() failed for commandline");
free(app_ptr);
free(name);
return;
}
app_ptr->zombie = false;
list_add_tail(&app_ptr->siblings, &supervisor_ptr->applist);
if (!loader_execute(supervisor_ptr->name, name, "/", terminal, commandline, &app_ptr->pid))
{
lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Execution of '%s' failed", commandline);
list_del(&app_ptr->siblings);
free(app_ptr->commandline);
free(app_ptr);
remove_app_internal(supervisor_ptr, app_ptr);
free(name);
return;
}
log_info("%s pid is %lu", app_ptr->name, (unsigned long)app_ptr->pid);
running = true;
terminal = app_ptr->terminal;
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);
emit_app_state_changed(supervisor_ptr, app_ptr);
method_return_new_void(call_ptr);
}

View File

@ -36,6 +36,25 @@ void ladish_app_supervisor_destroy(ladish_app_supervisor_handle supervisor_handl
bool ladish_app_supervisor_child_exit(ladish_app_supervisor_handle supervisor_handle, pid_t pid);
bool
ladish_app_supervisor_enum(
ladish_app_supervisor_handle supervisor_handle,
void * context,
bool (* callback)(void * context, const char * name, bool running, const char * command, bool terminal, uint8_t level));
void ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle);
bool
ladish_app_supervisor_add(
ladish_app_supervisor_handle supervisor_handle,
const char * name,
bool autorun,
const char * command,
bool terminal,
uint8_t level);
void ladish_app_supervisor_autorun(ladish_app_supervisor_handle supervisor_handle);
extern const struct dbus_interface_descriptor g_iface_app_supervisor;
#endif /* #ifndef APP_SUPERVISOR_H__712E6589_DCB1_4CE9_9812_4F250D55E8A2__INCLUDED */

View File

@ -31,6 +31,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <expat.h>
#include <limits.h>
#include "escape.h"
#include "cmd.h"
@ -49,9 +50,11 @@
#define PARSE_CONTEXT_KEY 10
#define PARSE_CONTEXT_CONNECTIONS 11
#define PARSE_CONTEXT_CONNECTION 12
#define PARSE_CONTEXT_APPLICATIONS 13
#define PARSE_CONTEXT_APPLICATION 14
#define MAX_STACK_DEPTH 10
#define MAX_DATA_SIZE 1024
#define MAX_DATA_SIZE 10240
struct parse_context
{
@ -65,6 +68,9 @@ struct parse_context
ladish_port_handle port;
ladish_dict_handle dict;
uint64_t connection_id;
bool terminal;
bool autorun;
uint8_t level;
};
#define context_ptr ((struct parse_context *)data)
@ -77,7 +83,8 @@ static void callback_chrdata(void * data, const XML_Char * s, int len)
}
if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER ||
context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_KEY)
context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_KEY ||
context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_APPLICATION)
{
if (context_ptr->data_used + len >= sizeof(context_ptr->data))
{
@ -97,6 +104,8 @@ static void callback_elstart(void * data, const char * el, const char ** attr)
uuid_t uuid2;
ladish_port_handle port1;
ladish_port_handle port2;
long int li_value;
char * end_ptr;
if (context_ptr->error)
{
@ -448,6 +457,83 @@ static void callback_elstart(void * data, const char * el, const char ** attr)
return;
}
if (strcmp(el, "applications") == 0)
{
//log_info("<applications>");
context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_APPLICATIONS;
return;
}
if (strcmp(el, "application") == 0)
{
//log_info("<application>");
context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_APPLICATION;
if (attr[0] == NULL ||
attr[1] == NULL ||
attr[2] == NULL ||
attr[3] == NULL ||
attr[4] == NULL ||
attr[5] == NULL ||
attr[6] == NULL ||
attr[7] == NULL ||
attr[8] != NULL ||
strcmp(attr[0], "name") != 0 ||
strcmp(attr[2], "terminal") != 0 ||
strcmp(attr[4], "level") != 0 ||
strcmp(attr[6], "autorun") != 0)
{
log_error("'application' XML element must contain exactly four attributes, named \"name\", \"terminal\", \"level\" and \"autorun\", in this order");
context_ptr->error = XML_TRUE;
return;
}
if (strcmp(attr[3], "true") != 0 && strcmp(attr[3], "false") != 0)
{
log_error("'application@terminal' XML attribute is boolean and the only valid values are \"true\" and \"false\"");
context_ptr->error = XML_TRUE;
return;
}
if (strcmp(attr[7], "true") != 0 && strcmp(attr[7], "false") != 0)
{
log_error("'application@autorun' XML attribute is boolean and the only valid values are \"true\" and \"false\"");
context_ptr->error = XML_TRUE;
return;
}
errno = 0; /* To distinguish success/failure after call */
li_value = strtol(attr[5], &end_ptr, 10);
if ((errno == ERANGE && (li_value == LONG_MAX || li_value == LONG_MIN)) || (errno != 0 && li_value == 0) || end_ptr == attr[5])
{
log_error("'application@level' XML attribute '%s' is not valid integer.", attr[5]);
context_ptr->error = XML_TRUE;
return;
}
if (li_value < 0 || li_value > 255)
{
log_error("'application@level' XML attribute '%s' is not valid uint8.", attr[5]);
context_ptr->error = XML_TRUE;
return;
}
context_ptr->str = strdup(attr[1]);
if (context_ptr->str == NULL)
{
log_error("strdup() failed");
context_ptr->error = XML_TRUE;
return;
}
context_ptr->terminal = strcmp(attr[3], "true") == 0;
context_ptr->autorun = strcmp(attr[7], "true") == 0;
context_ptr->level = (uint8_t)li_value;
context_ptr->data_used = 0;
return;
}
if (strcmp(el, "dict") == 0)
{
//log_info("<dict>");
@ -700,6 +786,17 @@ static void callback_elend(void * data, const char * el)
ASSERT(context_ptr->port != NULL);
context_ptr->port = NULL;
}
else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_APPLICATION)
{
context_ptr->data[context_ptr->data_used] = 0;
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))
{
log_error("ladish_app_supervisor_add() failed.");
context_ptr->error = XML_TRUE;
}
}
context_ptr->depth--;

View File

@ -557,6 +557,71 @@ bool save_studio_connection(void * context, ladish_port_handle port1_handle, lad
}
return true;
}
bool save_studio_app(void * context, const char * name, bool running, const char * command, bool terminal, uint8_t level)
{
char buf[100];
log_info("saving app: name='%s', %srunning, %s, level %u, commandline='%s'", name, running ? "" : "not ", terminal ? "terminal" : "shell", (unsigned int)level, command);
if (!write_string(fd, " <application name=\""))
{
return false;
}
if (!write_string(fd, name))
{
return false;
}
if (!write_string(fd, "\" terminal=\""))
{
return false;
}
if (!write_string(fd, terminal ? "true" : "false"))
{
return false;
}
if (!write_string(fd, "\" level=\""))
{
return false;
}
sprintf(buf, "%u", (unsigned int)level);
if (!write_string(fd, buf))
{
return false;
}
if (!write_string(fd, "\" autorun=\""))
{
return false;
}
if (!write_string(fd, running ? "true" : "false"))
{
return false;
}
if (!write_string(fd, "\">"))
{
return false;
}
if (!write_string(fd, command))
{
return false;
}
if (!write_string(fd, "</application>\n"))
{
return false;
}
return true;
}
@ -767,9 +832,24 @@ static bool run(void * command_context)
goto close;
}
if (!write_string(fd, " <applications>\n"))
{
goto close;
}
if (!ladish_app_supervisor_enum(g_studio.app_supervisor, &save_context, save_studio_app))
{
goto close;
}
if (!write_string(fd, " </applications>\n"))
{
goto close;
}
if (!write_dict(fd, " ", ladish_graph_get_dict(g_studio.studio_graph)))
{
return false;
goto close;
}
if (!write_string(fd, "</studio>\n"))

View File

@ -63,6 +63,8 @@ static bool run(void * context)
g_studio.filename = NULL;
}
ladish_app_supervisor_clear(g_studio.app_supervisor);
cmd_ptr->state = LADISH_COMMAND_STATE_DONE;
return true;
}

View File

@ -156,6 +156,8 @@ void on_event_jack_started(void)
}
}
ladish_app_supervisor_autorun(g_studio.app_supervisor);
emit_studio_started();
}