1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009, 2010 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of app supervisor object
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "config.h" /* Get _GNU_SOURCE defenition first to have some GNU extension available */
29 #include <sys/types.h>
32 #include "app_supervisor.h"
33 #include "../dbus/error.h"
34 #include "../dbus_constants.h"
36 #include "studio_internal.h"
37 #include "../proxies/notify_proxy.h"
41 struct list_head siblings
;
50 bool zombie
; /* if true, remove when stopped */
55 struct ladish_app_supervisor
62 struct list_head applist
;
63 void * on_app_renamed_context
;
64 ladish_app_supervisor_on_app_renamed_callback on_app_renamed
;
68 ladish_app_supervisor_create(
69 ladish_app_supervisor_handle
* supervisor_handle_ptr
,
73 ladish_app_supervisor_on_app_renamed_callback on_app_renamed
)
75 struct ladish_app_supervisor
* supervisor_ptr
;
77 supervisor_ptr
= malloc(sizeof(struct ladish_app_supervisor
));
78 if (supervisor_ptr
== NULL
)
80 log_error("malloc() failed to allocate struct ladish_app_supervisor");
84 supervisor_ptr
->opath
= strdup(opath
);
85 if (supervisor_ptr
->opath
== NULL
)
87 log_error("strdup() failed for app supervisor opath");
92 supervisor_ptr
->name
= strdup(name
);
93 if (supervisor_ptr
->name
== NULL
)
95 log_error("strdup() failed for app supervisor name");
96 free(supervisor_ptr
->opath
);
101 supervisor_ptr
->dir
= NULL
;
103 supervisor_ptr
->version
= 0;
104 supervisor_ptr
->next_id
= 1;
106 INIT_LIST_HEAD(&supervisor_ptr
->applist
);
108 supervisor_ptr
->on_app_renamed_context
= context
;
109 supervisor_ptr
->on_app_renamed
= on_app_renamed
;
111 *supervisor_handle_ptr
= (ladish_app_supervisor_handle
)supervisor_ptr
;
116 struct ladish_app
* ladish_app_supervisor_find_app_by_id_internal(struct ladish_app_supervisor
* supervisor_ptr
, uint64_t id
)
118 struct list_head
* node_ptr
;
119 struct ladish_app
* app_ptr
;
121 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
123 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
124 if (app_ptr
->id
== id
)
133 void remove_app_internal(struct ladish_app_supervisor
* supervisor_ptr
, struct ladish_app
* app_ptr
)
135 ASSERT(app_ptr
->pid
== 0); /* Removing not-stoped app? Zombies will make a rebellion! */
137 list_del(&app_ptr
->siblings
);
139 supervisor_ptr
->version
++;
143 supervisor_ptr
->opath
,
144 IFACE_APP_SUPERVISOR
,
147 &supervisor_ptr
->version
,
151 free(app_ptr
->commandline
);
155 void emit_app_state_changed(struct ladish_app_supervisor
* supervisor_ptr
, struct ladish_app
* app_ptr
)
158 dbus_bool_t terminal
;
160 running
= app_ptr
->pid
!= 0;
161 terminal
= app_ptr
->terminal
;
163 supervisor_ptr
->version
++;
167 supervisor_ptr
->opath
,
168 IFACE_APP_SUPERVISOR
,
171 &supervisor_ptr
->version
,
179 #define supervisor_ptr ((struct ladish_app_supervisor *)supervisor_handle)
181 const char * ladish_app_supervisor_get_opath(ladish_app_supervisor_handle supervisor_handle
)
183 return supervisor_ptr
->opath
;
186 ladish_app_handle
ladish_app_supervisor_find_app_by_name(ladish_app_supervisor_handle supervisor_handle
, const char * name
)
188 struct list_head
* node_ptr
;
189 struct ladish_app
* app_ptr
;
191 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
193 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
194 if (strcmp(app_ptr
->name
, name
) == 0)
196 return (ladish_app_handle
)app_ptr
;
203 ladish_app_handle
ladish_app_supervisor_find_app_by_id(ladish_app_supervisor_handle supervisor_handle
, uint64_t id
)
205 return (ladish_app_handle
)ladish_app_supervisor_find_app_by_id_internal(supervisor_ptr
, id
);
208 ladish_app_handle
ladish_app_supervisor_find_app_by_pid(ladish_app_supervisor_handle supervisor_handle
, pid_t pid
)
210 struct list_head
* node_ptr
;
211 struct ladish_app
* app_ptr
;
213 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
215 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
216 if (app_ptr
->pid
== pid
)
218 //log_info("app \"%s\" found by pid %llu", app_ptr->name, (unsigned long long)pid);
219 return (ladish_app_handle
)app_ptr
;
227 ladish_app_supervisor_add(
228 ladish_app_supervisor_handle supervisor_handle
,
231 const char * command
,
235 struct ladish_app
* app_ptr
;
238 app_ptr
= malloc(sizeof(struct ladish_app
));
241 log_error("malloc of struct ladish_app failed");
245 app_ptr
->name
= strdup(name
);
246 if (app_ptr
->name
== NULL
)
248 log_error("strdup() failed for app name");
253 app_ptr
->commandline
= strdup(command
);
254 if (app_ptr
->commandline
== NULL
)
256 log_error("strdup() failed for app commandline");
262 app_ptr
->terminal
= terminal
;
263 app_ptr
->level
= level
;
265 app_ptr
->firstborn_pid
= 0;
267 app_ptr
->id
= supervisor_ptr
->next_id
++;
268 uuid_generate(app_ptr
->uuid
);
269 app_ptr
->zombie
= false;
270 app_ptr
->state
= LADISH_APP_STATE_STOPPED
;
271 app_ptr
->autorun
= autorun
;
272 list_add_tail(&app_ptr
->siblings
, &supervisor_ptr
->applist
);
274 supervisor_ptr
->version
++;
279 supervisor_ptr
->opath
,
280 IFACE_APP_SUPERVISOR
,
283 &supervisor_ptr
->version
,
290 return (ladish_app_handle
)app_ptr
;
293 static void ladish_app_send_signal(struct ladish_app
* app_ptr
, int sig
, bool prefer_firstborn
)
296 const char * signal_name
;
298 ASSERT(app_ptr
->state
= LADISH_APP_STATE_STARTED
);
299 if (app_ptr
->pid
<= 0)
305 if (prefer_firstborn
&& app_ptr
->firstborn_pid
!= 0)
307 pid
= app_ptr
->firstborn_pid
;
317 signal_name
= "SIGTERM";
320 signal_name
= "SIGKILL";
323 signal_name
= "SIGUSR1";
326 signal_name
= strsignal(sig
);
327 if (signal_name
== NULL
)
329 signal_name
= "unknown";
333 log_info("sending signal %d (%s) to '%s' with pid %u", sig
, signal_name
, app_ptr
->name
, (unsigned int)pid
);
338 bool ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle
)
340 struct list_head
* node_ptr
;
341 struct list_head
* safe_node_ptr
;
342 struct ladish_app
* app_ptr
;
345 if (supervisor_ptr
->dir
!= NULL
)
347 free(supervisor_ptr
->dir
);
348 supervisor_ptr
->dir
= NULL
;
353 list_for_each_safe(node_ptr
, safe_node_ptr
, &supervisor_ptr
->applist
)
355 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
356 if (app_ptr
->pid
!= 0)
358 log_info("terminating '%s'...", app_ptr
->name
);
359 ladish_app_send_signal(app_ptr
, SIGTERM
, false);
360 app_ptr
->zombie
= true;
361 app_ptr
->state
= LADISH_APP_STATE_STOPPING
;
366 log_info("removing '%s'", app_ptr
->name
);
367 remove_app_internal(supervisor_ptr
, app_ptr
);
374 void ladish_app_supervisor_destroy(ladish_app_supervisor_handle supervisor_handle
)
376 ladish_app_supervisor_clear(supervisor_handle
);
377 free(supervisor_ptr
->name
);
378 free(supervisor_ptr
->opath
);
379 free(supervisor_ptr
);
383 ladish_app_supervisor_set_directory(
384 ladish_app_supervisor_handle supervisor_handle
,
392 log_error("strdup(\"%s\") failed", dir
);
396 if (supervisor_ptr
->dir
!= NULL
)
398 free(supervisor_ptr
->dir
);
401 supervisor_ptr
->dir
= dup
;
406 bool ladish_app_supervisor_child_exit(ladish_app_supervisor_handle supervisor_handle
, pid_t pid
)
408 struct list_head
* node_ptr
;
409 struct ladish_app
* app_ptr
;
411 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
413 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
414 if (app_ptr
->pid
== pid
)
416 log_info("exit of child '%s' detected.", app_ptr
->name
);
419 app_ptr
->firstborn_pid
= 0;
422 remove_app_internal(supervisor_ptr
, app_ptr
);
426 if (app_ptr
->state
== LADISH_APP_STATE_STARTED
)
428 ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH
, "App terminated unexpectedly", app_ptr
->name
);
431 app_ptr
->state
= LADISH_APP_STATE_STOPPED
;
433 emit_app_state_changed(supervisor_ptr
, app_ptr
);
444 ladish_app_supervisor_enum(
445 ladish_app_supervisor_handle supervisor_handle
,
447 ladish_app_supervisor_enum_callback callback
)
449 struct list_head
* node_ptr
;
450 struct ladish_app
* app_ptr
;
452 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
454 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
456 if (!callback(context
, app_ptr
->name
, app_ptr
->pid
!= 0, app_ptr
->commandline
, app_ptr
->terminal
, app_ptr
->level
, app_ptr
->pid
, app_ptr
->uuid
))
465 static inline void ladish_app_save_L1_internal(struct ladish_app
* app_ptr
)
467 if (app_ptr
->level
== 1)
469 ladish_app_send_signal(app_ptr
, SIGUSR1
, true);
473 #define app_ptr ((struct ladish_app *)app_handle)
475 bool ladish_app_supervisor_start_app(ladish_app_supervisor_handle supervisor_handle
, ladish_app_handle app_handle
)
477 app_ptr
->zombie
= false;
479 ASSERT(app_ptr
->pid
== 0);
482 supervisor_ptr
->name
,
484 supervisor_ptr
->dir
!= NULL
? supervisor_ptr
->dir
: "/",
486 app_ptr
->commandline
,
492 ASSERT(app_ptr
->pid
!= 0);
493 app_ptr
->state
= LADISH_APP_STATE_STARTED
;
495 emit_app_state_changed(supervisor_ptr
, app_ptr
);
499 void ladish_app_supervisor_remove_app(ladish_app_supervisor_handle supervisor_handle
, ladish_app_handle app_handle
)
501 remove_app_internal(supervisor_ptr
, app_ptr
);
504 unsigned int ladish_app_get_state(ladish_app_handle app_handle
)
506 return app_ptr
->state
;
509 bool ladish_app_is_running(ladish_app_handle app_handle
)
511 return app_ptr
->pid
!= 0;
514 const char * ladish_app_get_name(ladish_app_handle app_handle
)
516 return app_ptr
->name
;
519 void ladish_app_get_uuid(ladish_app_handle app_handle
, uuid_t uuid
)
521 uuid_copy(uuid
, app_ptr
->uuid
);
524 void ladish_app_stop(ladish_app_handle app_handle
)
526 ladish_app_send_signal(app_ptr
, SIGTERM
, false);
527 app_ptr
->state
= LADISH_APP_STATE_STOPPING
;
530 void ladish_app_kill(ladish_app_handle app_handle
)
532 ladish_app_send_signal(app_ptr
, SIGKILL
, false);
533 app_ptr
->state
= LADISH_APP_STATE_KILL
;
536 void ladish_app_save_L1(ladish_app_handle app_handle
)
538 ladish_app_save_L1_internal(app_ptr
);
541 void ladish_app_add_pid(ladish_app_handle app_handle
, pid_t pid
)
543 if (app_ptr
->pid
== 0)
545 log_error("Associating pid with stopped app does not make sense");
550 if (pid
<= 1) /* catch -1, 0 and 1 */
552 log_error("Refusing domination by ignoring pid %d", (int)pid
);
557 if (app_ptr
->pid
== pid
)
558 { /* The top level process that is already known */
562 if (app_ptr
->firstborn_pid
!= 0)
563 { /* Ignore non-first children */
567 log_info("First grandchild with pid %u", (unsigned int)pid
);
568 app_ptr
->firstborn_pid
= pid
;
573 void ladish_app_supervisor_autorun(ladish_app_supervisor_handle supervisor_handle
)
575 struct list_head
* node_ptr
;
576 struct ladish_app
* app_ptr
;
578 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
580 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
582 if (!app_ptr
->autorun
)
587 app_ptr
->autorun
= false;
589 log_info("autorun('%s', %s, '%s') called", app_ptr
->name
, app_ptr
->terminal
? "terminal" : "shell", app_ptr
->commandline
);
591 if (!ladish_app_supervisor_start_app((ladish_app_supervisor_handle
)supervisor_ptr
, (ladish_app_handle
)app_ptr
))
593 log_error("Execution of '%s' failed", app_ptr
->commandline
);
599 void ladish_app_supervisor_stop(ladish_app_supervisor_handle supervisor_handle
)
601 struct list_head
* node_ptr
;
602 struct ladish_app
* app_ptr
;
604 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
606 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
607 if (app_ptr
->pid
!= 0)
609 log_info("terminating '%s'...", app_ptr
->name
);
610 ladish_app_send_signal(app_ptr
, SIGTERM
, false);
611 app_ptr
->autorun
= true;
612 app_ptr
->state
= LADISH_APP_STATE_STOPPING
;
617 void ladish_app_supervisor_save_L1(ladish_app_supervisor_handle supervisor_handle
)
619 struct list_head
* node_ptr
;
620 struct ladish_app
* app_ptr
;
622 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
624 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
625 if (app_ptr
->state
!= LADISH_APP_STATE_STARTED
)
630 if (app_ptr
->pid
== 0)
636 ladish_app_save_L1_internal(app_ptr
);
640 const char * ladish_app_supervisor_get_name(ladish_app_supervisor_handle supervisor_handle
)
642 return supervisor_ptr
->name
;
645 unsigned int ladish_app_supervisor_get_running_app_count(ladish_app_supervisor_handle supervisor_handle
)
647 struct list_head
* node_ptr
;
648 struct ladish_app
* app_ptr
;
649 unsigned int counter
;
652 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
654 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
655 if (app_ptr
->pid
!= 0)
664 bool ladish_app_supervisor_has_apps(ladish_app_supervisor_handle supervisor_handle
)
666 return !list_empty(&supervisor_ptr
->applist
);
669 #undef supervisor_ptr
671 /**********************************************************************************/
673 /**********************************************************************************/
675 #define supervisor_ptr ((struct ladish_app_supervisor *)call_ptr->iface_context)
677 static void get_all(struct dbus_method_call
* call_ptr
)
679 DBusMessageIter iter
, array_iter
, struct_iter
;
680 struct list_head
* node_ptr
;
681 struct ladish_app
* app_ptr
;
683 dbus_bool_t terminal
;
685 //log_info("get_all called");
687 call_ptr
->reply
= dbus_message_new_method_return(call_ptr
->message
);
688 if (call_ptr
->reply
== NULL
)
693 dbus_message_iter_init_append(call_ptr
->reply
, &iter
);
695 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_UINT64
, &supervisor_ptr
->version
))
700 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(tsbby)", &array_iter
))
705 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
707 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
709 log_info("app '%s' (%llu)", app_ptr
->name
, (unsigned long long)app_ptr
->id
);
711 if (!dbus_message_iter_open_container (&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
))
716 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT64
, &app_ptr
->id
))
721 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_STRING
, &app_ptr
->name
))
726 running
= app_ptr
->pid
!= 0;
727 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_BOOLEAN
, &running
))
732 terminal
= app_ptr
->terminal
;
733 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_BOOLEAN
, &terminal
))
738 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_BYTE
, &app_ptr
->level
))
743 if (!dbus_message_iter_close_container(&array_iter
, &struct_iter
))
749 if (!dbus_message_iter_close_container(&iter
, &array_iter
))
757 dbus_message_unref(call_ptr
->reply
);
758 call_ptr
->reply
= NULL
;
761 log_error("Ran out of memory trying to construct method return");
764 static void run_custom(struct dbus_method_call
* call_ptr
)
766 dbus_bool_t terminal
;
767 const char * commandline
;
771 if (!dbus_message_get_args(
774 DBUS_TYPE_BOOLEAN
, &terminal
,
775 DBUS_TYPE_STRING
, &commandline
,
776 DBUS_TYPE_STRING
, &name
,
777 DBUS_TYPE_BYTE
, &level
,
780 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
781 dbus_error_free(&g_dbus_error
);
785 log_info("run_custom('%s', %s, '%s', %"PRIu8
") called", name
, terminal
? "terminal" : "shell", commandline
, level
);
787 if (level
!= 0 && level
!= 1)
789 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "invalid level %"PRIu8
, level
);
793 if (ladish_command_new_app(
795 ladish_studio_get_cmd_queue(),
796 supervisor_ptr
->opath
,
802 method_return_new_void(call_ptr
);
806 static void start_app(struct dbus_method_call
* call_ptr
)
810 if (!dbus_message_get_args(
813 DBUS_TYPE_UINT64
, &id
,
816 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
817 dbus_error_free(&g_dbus_error
);
821 if (ladish_command_change_app_state(call_ptr
, ladish_studio_get_cmd_queue(), supervisor_ptr
->opath
, id
, LADISH_APP_STATE_STARTED
))
823 method_return_new_void(call_ptr
);
827 static void stop_app(struct dbus_method_call
* call_ptr
)
831 if (!dbus_message_get_args(
834 DBUS_TYPE_UINT64
, &id
,
837 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
838 dbus_error_free(&g_dbus_error
);
842 if (ladish_command_change_app_state(call_ptr
, ladish_studio_get_cmd_queue(), supervisor_ptr
->opath
, id
, LADISH_APP_STATE_STOPPED
))
844 method_return_new_void(call_ptr
);
848 static void kill_app(struct dbus_method_call
* call_ptr
)
852 if (!dbus_message_get_args(
855 DBUS_TYPE_UINT64
, &id
,
858 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
859 dbus_error_free(&g_dbus_error
);
863 if (ladish_command_change_app_state(call_ptr
, ladish_studio_get_cmd_queue(), supervisor_ptr
->opath
, id
, LADISH_APP_STATE_KILL
))
865 method_return_new_void(call_ptr
);
869 static void get_app_properties(struct dbus_method_call
* call_ptr
)
872 struct ladish_app
* app_ptr
;
874 dbus_bool_t terminal
;
876 if (!dbus_message_get_args(
879 DBUS_TYPE_UINT64
, &id
,
882 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
883 dbus_error_free(&g_dbus_error
);
887 app_ptr
= ladish_app_supervisor_find_app_by_id_internal(supervisor_ptr
, id
);
890 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "App with ID %"PRIu64
" not found", id
);
894 running
= app_ptr
->pid
!= 0;
895 terminal
= app_ptr
->terminal
;
897 call_ptr
->reply
= dbus_message_new_method_return(call_ptr
->message
);
898 if (call_ptr
->reply
== NULL
)
903 if (!dbus_message_append_args(
905 DBUS_TYPE_STRING
, &app_ptr
->name
,
906 DBUS_TYPE_STRING
, &app_ptr
->commandline
,
907 DBUS_TYPE_BOOLEAN
, &running
,
908 DBUS_TYPE_BOOLEAN
, &terminal
,
909 DBUS_TYPE_BYTE
, &app_ptr
->level
,
918 dbus_message_unref(call_ptr
->reply
);
919 call_ptr
->reply
= NULL
;
922 log_error("Ran out of memory trying to construct method return");
925 static void set_app_properties(struct dbus_method_call
* call_ptr
)
928 dbus_bool_t terminal
;
930 const char * commandline
;
932 struct ladish_app
* app_ptr
;
934 char * commandline_buffer
;
936 if (!dbus_message_get_args(
939 DBUS_TYPE_UINT64
, &id
,
940 DBUS_TYPE_STRING
, &name
,
941 DBUS_TYPE_STRING
, &commandline
,
942 DBUS_TYPE_BOOLEAN
, &terminal
,
943 DBUS_TYPE_BYTE
, &level
,
946 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
947 dbus_error_free(&g_dbus_error
);
951 app_ptr
= ladish_app_supervisor_find_app_by_id_internal(supervisor_ptr
, id
);
954 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "App with ID %"PRIu64
" not found", id
);
958 if (app_ptr
->pid
!= 0 && strcmp(commandline
, app_ptr
->commandline
) != 0)
960 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Cannot change commandline when app is running. '%s' -> '%s'", app_ptr
->commandline
, commandline
);
964 if (app_ptr
->pid
!= 0 && ((app_ptr
->terminal
&& !terminal
) || (!app_ptr
->terminal
&& terminal
)))
966 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Cannot change whether to run in terminal when app is running");
970 if (app_ptr
->pid
!= 0 && app_ptr
->level
!= level
)
972 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Cannot change app level when app is running");
976 if (strcmp(commandline
, app_ptr
->commandline
) != 0)
978 commandline_buffer
= strdup(commandline
);
979 if (commandline_buffer
== NULL
)
981 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "strdup() failed for app commandline");
987 commandline_buffer
= NULL
;
990 if (strcmp(name
, app_ptr
->name
) != 0)
992 name_buffer
= strdup(name
);
993 if (name_buffer
== NULL
)
995 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "strdup() failed for app nam");
996 if (commandline_buffer
!= NULL
)
998 free(commandline_buffer
);
1008 if (name_buffer
!= NULL
)
1010 supervisor_ptr
->on_app_renamed(supervisor_ptr
->on_app_renamed_context
, app_ptr
->uuid
, app_ptr
->name
, name_buffer
);
1011 free(app_ptr
->name
);
1012 app_ptr
->name
= name_buffer
;
1015 if (commandline_buffer
!= NULL
)
1017 free(app_ptr
->commandline
);
1018 app_ptr
->commandline
= commandline_buffer
;
1021 app_ptr
->level
= level
;
1022 app_ptr
->terminal
= terminal
;
1024 emit_app_state_changed(supervisor_ptr
, app_ptr
);
1026 method_return_new_void(call_ptr
);
1029 static void remove_app(struct dbus_method_call
* call_ptr
)
1033 if (!dbus_message_get_args(
1036 DBUS_TYPE_UINT64
, &id
,
1039 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
1040 dbus_error_free(&g_dbus_error
);
1044 if (ladish_command_remove_app(call_ptr
, ladish_studio_get_cmd_queue(), supervisor_ptr
->opath
, id
))
1046 method_return_new_void(call_ptr
);
1050 static void is_app_running(struct dbus_method_call
* call_ptr
)
1053 struct ladish_app
* app_ptr
;
1054 dbus_bool_t running
;
1056 if (!dbus_message_get_args(
1059 DBUS_TYPE_UINT64
, &id
,
1062 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
1063 dbus_error_free(&g_dbus_error
);
1067 app_ptr
= ladish_app_supervisor_find_app_by_id_internal(supervisor_ptr
, id
);
1068 if (app_ptr
== NULL
)
1070 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "App with ID %"PRIu64
" not found", id
);
1074 running
= app_ptr
->pid
!= 0;
1076 method_return_new_single(call_ptr
, DBUS_TYPE_BOOLEAN
, &running
);
1079 #undef supervisor_ptr
1081 METHOD_ARGS_BEGIN(GetAll
, "Get list of apps")
1082 METHOD_ARG_DESCRIBE_OUT("list_version", DBUS_TYPE_UINT64_AS_STRING
, "Version of the list")
1083 METHOD_ARG_DESCRIBE_OUT("apps_list", "a(tsbby)", "List of apps")
1086 METHOD_ARGS_BEGIN(RunCustom
, "Start application by supplying commandline")
1087 METHOD_ARG_DESCRIBE_IN("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1088 METHOD_ARG_DESCRIBE_IN("commandline", DBUS_TYPE_STRING_AS_STRING
, "Commandline")
1089 METHOD_ARG_DESCRIBE_IN("name", DBUS_TYPE_STRING_AS_STRING
, "Name")
1090 METHOD_ARG_DESCRIBE_IN("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1093 METHOD_ARGS_BEGIN(StartApp
, "Start application")
1094 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1097 METHOD_ARGS_BEGIN(StopApp
, "Stop application")
1098 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1101 METHOD_ARGS_BEGIN(KillApp
, "Kill application")
1102 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1105 METHOD_ARGS_BEGIN(RemoveApp
, "Remove application")
1106 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1109 METHOD_ARGS_BEGIN(GetAppProperties
, "Get properties of an application")
1110 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1111 METHOD_ARG_DESCRIBE_OUT("name", DBUS_TYPE_STRING_AS_STRING
, "")
1112 METHOD_ARG_DESCRIBE_OUT("commandline", DBUS_TYPE_STRING_AS_STRING
, "Commandline")
1113 METHOD_ARG_DESCRIBE_OUT("running", DBUS_TYPE_BOOLEAN_AS_STRING
, "")
1114 METHOD_ARG_DESCRIBE_OUT("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1115 METHOD_ARG_DESCRIBE_OUT("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1118 METHOD_ARGS_BEGIN(SetAppProperties
, "Set properties of an application")
1119 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1120 METHOD_ARG_DESCRIBE_IN("name", DBUS_TYPE_STRING_AS_STRING
, "")
1121 METHOD_ARG_DESCRIBE_IN("commandline", DBUS_TYPE_STRING_AS_STRING
, "Commandline")
1122 METHOD_ARG_DESCRIBE_IN("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1123 METHOD_ARG_DESCRIBE_IN("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1126 METHOD_ARGS_BEGIN(IsAppRunning
, "Check whether application is running")
1127 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1128 METHOD_ARG_DESCRIBE_OUT("running", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether app is running")
1133 METHOD_DESCRIBE(GetAll
, get_all
) /* sync */
1134 METHOD_DESCRIBE(RunCustom
, run_custom
) /* async */
1135 METHOD_DESCRIBE(StartApp
, start_app
) /* async */
1136 METHOD_DESCRIBE(StopApp
, stop_app
) /* async */
1137 METHOD_DESCRIBE(KillApp
, kill_app
) /* async */
1138 METHOD_DESCRIBE(GetAppProperties
, get_app_properties
) /* sync */
1139 METHOD_DESCRIBE(SetAppProperties
, set_app_properties
) /* sync */
1140 METHOD_DESCRIBE(RemoveApp
, remove_app
) /* sync */
1141 METHOD_DESCRIBE(IsAppRunning
, is_app_running
) /* sync */
1144 SIGNAL_ARGS_BEGIN(AppAdded
, "")
1145 SIGNAL_ARG_DESCRIBE("new_list_version", DBUS_TYPE_UINT64_AS_STRING
, "")
1146 SIGNAL_ARG_DESCRIBE("id", DBUS_TYPE_UINT64_AS_STRING
, "")
1147 SIGNAL_ARG_DESCRIBE("name", DBUS_TYPE_STRING_AS_STRING
, "")
1148 SIGNAL_ARG_DESCRIBE("running", DBUS_TYPE_BOOLEAN_AS_STRING
, "")
1149 SIGNAL_ARG_DESCRIBE("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1150 SIGNAL_ARG_DESCRIBE("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1153 SIGNAL_ARGS_BEGIN(AppRemoved
, "")
1154 SIGNAL_ARG_DESCRIBE("new_list_version", DBUS_TYPE_UINT64_AS_STRING
, "")
1155 SIGNAL_ARG_DESCRIBE("id", DBUS_TYPE_UINT64_AS_STRING
, "")
1158 SIGNAL_ARGS_BEGIN(AppStateChanged
, "")
1159 SIGNAL_ARG_DESCRIBE("new_list_version", DBUS_TYPE_UINT64_AS_STRING
, "")
1160 SIGNAL_ARG_DESCRIBE("id", DBUS_TYPE_UINT64_AS_STRING
, "")
1161 SIGNAL_ARG_DESCRIBE("name", DBUS_TYPE_STRING_AS_STRING
, "")
1162 SIGNAL_ARG_DESCRIBE("running", DBUS_TYPE_BOOLEAN_AS_STRING
, "")
1163 SIGNAL_ARG_DESCRIBE("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1164 SIGNAL_ARG_DESCRIBE("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1168 SIGNAL_DESCRIBE(AppAdded
)
1169 SIGNAL_DESCRIBE(AppRemoved
)
1170 SIGNAL_DESCRIBE(AppStateChanged
)
1173 INTERFACE_BEGIN(g_iface_app_supervisor
, IFACE_APP_SUPERVISOR
)
1174 INTERFACE_DEFAULT_HANDLER
1175 INTERFACE_EXPOSE_METHODS
1176 INTERFACE_EXPOSE_SIGNALS