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
63 struct list_head applist
;
64 void * on_app_renamed_context
;
65 ladish_app_supervisor_on_app_renamed_callback on_app_renamed
;
69 ladish_app_supervisor_create(
70 ladish_app_supervisor_handle
* supervisor_handle_ptr
,
74 ladish_app_supervisor_on_app_renamed_callback on_app_renamed
)
76 struct ladish_app_supervisor
* supervisor_ptr
;
78 supervisor_ptr
= malloc(sizeof(struct ladish_app_supervisor
));
79 if (supervisor_ptr
== NULL
)
81 log_error("malloc() failed to allocate struct ladish_app_supervisor");
85 supervisor_ptr
->opath
= strdup(opath
);
86 if (supervisor_ptr
->opath
== NULL
)
88 log_error("strdup() failed for app supervisor opath");
93 supervisor_ptr
->name
= strdup(name
);
94 if (supervisor_ptr
->name
== NULL
)
96 log_error("strdup() failed for app supervisor name");
97 free(supervisor_ptr
->opath
);
102 supervisor_ptr
->dir
= NULL
;
103 supervisor_ptr
->project_name
= NULL
;
105 supervisor_ptr
->version
= 0;
106 supervisor_ptr
->next_id
= 1;
108 INIT_LIST_HEAD(&supervisor_ptr
->applist
);
110 supervisor_ptr
->on_app_renamed_context
= context
;
111 supervisor_ptr
->on_app_renamed
= on_app_renamed
;
113 *supervisor_handle_ptr
= (ladish_app_supervisor_handle
)supervisor_ptr
;
118 struct ladish_app
* ladish_app_supervisor_find_app_by_id_internal(struct ladish_app_supervisor
* supervisor_ptr
, uint64_t id
)
120 struct list_head
* node_ptr
;
121 struct ladish_app
* app_ptr
;
123 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
125 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
126 if (app_ptr
->id
== id
)
135 void remove_app_internal(struct ladish_app_supervisor
* supervisor_ptr
, struct ladish_app
* app_ptr
)
137 ASSERT(app_ptr
->pid
== 0); /* Removing not-stoped app? Zombies will make a rebellion! */
139 list_del(&app_ptr
->siblings
);
141 supervisor_ptr
->version
++;
145 supervisor_ptr
->opath
,
146 IFACE_APP_SUPERVISOR
,
149 &supervisor_ptr
->version
,
153 free(app_ptr
->commandline
);
157 void emit_app_state_changed(struct ladish_app_supervisor
* supervisor_ptr
, struct ladish_app
* app_ptr
)
160 dbus_bool_t terminal
;
162 running
= app_ptr
->pid
!= 0;
163 terminal
= app_ptr
->terminal
;
165 supervisor_ptr
->version
++;
169 supervisor_ptr
->opath
,
170 IFACE_APP_SUPERVISOR
,
173 &supervisor_ptr
->version
,
181 #define supervisor_ptr ((struct ladish_app_supervisor *)supervisor_handle)
183 const char * ladish_app_supervisor_get_opath(ladish_app_supervisor_handle supervisor_handle
)
185 return supervisor_ptr
->opath
;
188 ladish_app_handle
ladish_app_supervisor_find_app_by_name(ladish_app_supervisor_handle supervisor_handle
, const char * name
)
190 struct list_head
* node_ptr
;
191 struct ladish_app
* app_ptr
;
193 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
195 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
196 if (strcmp(app_ptr
->name
, name
) == 0)
198 return (ladish_app_handle
)app_ptr
;
205 ladish_app_handle
ladish_app_supervisor_find_app_by_id(ladish_app_supervisor_handle supervisor_handle
, uint64_t id
)
207 return (ladish_app_handle
)ladish_app_supervisor_find_app_by_id_internal(supervisor_ptr
, id
);
210 ladish_app_handle
ladish_app_supervisor_find_app_by_pid(ladish_app_supervisor_handle supervisor_handle
, pid_t pid
)
212 struct list_head
* node_ptr
;
213 struct ladish_app
* app_ptr
;
215 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
217 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
218 if (app_ptr
->pid
== pid
)
220 //log_info("app \"%s\" found by pid %llu", app_ptr->name, (unsigned long long)pid);
221 return (ladish_app_handle
)app_ptr
;
228 ladish_app_handle
ladish_app_supervisor_find_app_by_uuid(ladish_app_supervisor_handle supervisor_handle
, const uuid_t uuid
)
230 struct list_head
* node_ptr
;
231 struct ladish_app
* app_ptr
;
233 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
235 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
236 if (uuid_compare(app_ptr
->uuid
, uuid
) == 0)
238 return (ladish_app_handle
)app_ptr
;
246 ladish_app_supervisor_add(
247 ladish_app_supervisor_handle supervisor_handle
,
250 const char * command
,
254 struct ladish_app
* app_ptr
;
257 app_ptr
= malloc(sizeof(struct ladish_app
));
260 log_error("malloc of struct ladish_app failed");
264 app_ptr
->name
= strdup(name
);
265 if (app_ptr
->name
== NULL
)
267 log_error("strdup() failed for app name");
272 app_ptr
->commandline
= strdup(command
);
273 if (app_ptr
->commandline
== NULL
)
275 log_error("strdup() failed for app commandline");
281 app_ptr
->terminal
= terminal
;
282 app_ptr
->level
= level
;
284 app_ptr
->firstborn_pid
= 0;
286 app_ptr
->id
= supervisor_ptr
->next_id
++;
287 uuid_generate(app_ptr
->uuid
);
288 app_ptr
->zombie
= false;
289 app_ptr
->state
= LADISH_APP_STATE_STOPPED
;
290 app_ptr
->autorun
= autorun
;
291 list_add_tail(&app_ptr
->siblings
, &supervisor_ptr
->applist
);
293 supervisor_ptr
->version
++;
298 supervisor_ptr
->opath
,
299 IFACE_APP_SUPERVISOR
,
302 &supervisor_ptr
->version
,
309 return (ladish_app_handle
)app_ptr
;
312 static void ladish_app_send_signal(struct ladish_app
* app_ptr
, int sig
, bool prefer_firstborn
)
315 const char * signal_name
;
317 ASSERT(app_ptr
->state
= LADISH_APP_STATE_STARTED
);
318 if (app_ptr
->pid
<= 0)
324 if (prefer_firstborn
&& app_ptr
->firstborn_pid
!= 0)
326 pid
= app_ptr
->firstborn_pid
;
336 signal_name
= "SIGTERM";
339 signal_name
= "SIGKILL";
342 signal_name
= "SIGUSR1";
345 signal_name
= strsignal(sig
);
346 if (signal_name
== NULL
)
348 signal_name
= "unknown";
352 log_info("sending signal %d (%s) to '%s' with pid %u", sig
, signal_name
, app_ptr
->name
, (unsigned int)pid
);
357 bool ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle
)
359 struct list_head
* node_ptr
;
360 struct list_head
* safe_node_ptr
;
361 struct ladish_app
* app_ptr
;
364 free(supervisor_ptr
->dir
);
365 supervisor_ptr
->dir
= NULL
;
367 free(supervisor_ptr
->project_name
);
368 supervisor_ptr
->project_name
= NULL
;
372 list_for_each_safe(node_ptr
, safe_node_ptr
, &supervisor_ptr
->applist
)
374 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
375 if (app_ptr
->pid
!= 0)
377 log_info("terminating '%s'...", app_ptr
->name
);
378 ladish_app_send_signal(app_ptr
, SIGTERM
, false);
379 app_ptr
->zombie
= true;
380 app_ptr
->state
= LADISH_APP_STATE_STOPPING
;
385 log_info("removing '%s'", app_ptr
->name
);
386 remove_app_internal(supervisor_ptr
, app_ptr
);
393 void ladish_app_supervisor_destroy(ladish_app_supervisor_handle supervisor_handle
)
395 ladish_app_supervisor_clear(supervisor_handle
);
396 free(supervisor_ptr
->name
);
397 free(supervisor_ptr
->opath
);
398 free(supervisor_ptr
);
402 ladish_app_supervisor_set_directory(
403 ladish_app_supervisor_handle supervisor_handle
,
411 log_error("strdup(\"%s\") failed", dir
);
415 if (supervisor_ptr
->dir
!= NULL
)
417 free(supervisor_ptr
->dir
);
420 supervisor_ptr
->dir
= dup
;
426 ladish_app_supervisor_set_project_name(
427 ladish_app_supervisor_handle supervisor_handle
,
428 const char * project_name
)
432 if (project_name
!= NULL
)
434 dup
= strdup(project_name
);
437 log_error("strdup(\"%s\") failed", project_name
);
446 free(supervisor_ptr
->project_name
);
447 supervisor_ptr
->project_name
= dup
;
452 bool ladish_app_supervisor_child_exit(ladish_app_supervisor_handle supervisor_handle
, pid_t pid
)
454 struct list_head
* node_ptr
;
455 struct ladish_app
* app_ptr
;
457 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
459 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
460 if (app_ptr
->pid
== pid
)
462 log_info("exit of child '%s' detected.", app_ptr
->name
);
465 app_ptr
->firstborn_pid
= 0;
468 remove_app_internal(supervisor_ptr
, app_ptr
);
472 if (app_ptr
->state
== LADISH_APP_STATE_STARTED
)
474 ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH
, "App terminated unexpectedly", app_ptr
->name
);
477 app_ptr
->state
= LADISH_APP_STATE_STOPPED
;
479 emit_app_state_changed(supervisor_ptr
, app_ptr
);
490 ladish_app_supervisor_enum(
491 ladish_app_supervisor_handle supervisor_handle
,
493 ladish_app_supervisor_enum_callback callback
)
495 struct list_head
* node_ptr
;
496 struct ladish_app
* app_ptr
;
498 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
500 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
502 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
))
511 static inline void ladish_app_save_L1_internal(struct ladish_app
* app_ptr
)
513 if (app_ptr
->level
== 1)
515 ladish_app_send_signal(app_ptr
, SIGUSR1
, true);
519 #define app_ptr ((struct ladish_app *)app_handle)
521 bool ladish_app_supervisor_start_app(ladish_app_supervisor_handle supervisor_handle
, ladish_app_handle app_handle
)
523 app_ptr
->zombie
= false;
525 ASSERT(app_ptr
->pid
== 0);
528 supervisor_ptr
->name
,
529 supervisor_ptr
->project_name
,
531 supervisor_ptr
->dir
!= NULL
? supervisor_ptr
->dir
: "/",
533 app_ptr
->commandline
,
539 ASSERT(app_ptr
->pid
!= 0);
540 app_ptr
->state
= LADISH_APP_STATE_STARTED
;
542 emit_app_state_changed(supervisor_ptr
, app_ptr
);
546 void ladish_app_supervisor_remove_app(ladish_app_supervisor_handle supervisor_handle
, ladish_app_handle app_handle
)
548 remove_app_internal(supervisor_ptr
, app_ptr
);
551 unsigned int ladish_app_get_state(ladish_app_handle app_handle
)
553 return app_ptr
->state
;
556 bool ladish_app_is_running(ladish_app_handle app_handle
)
558 return app_ptr
->pid
!= 0;
561 const char * ladish_app_get_name(ladish_app_handle app_handle
)
563 return app_ptr
->name
;
566 void ladish_app_get_uuid(ladish_app_handle app_handle
, uuid_t uuid
)
568 uuid_copy(uuid
, app_ptr
->uuid
);
571 void ladish_app_stop(ladish_app_handle app_handle
)
573 ladish_app_send_signal(app_ptr
, SIGTERM
, false);
574 app_ptr
->state
= LADISH_APP_STATE_STOPPING
;
577 void ladish_app_kill(ladish_app_handle app_handle
)
579 ladish_app_send_signal(app_ptr
, SIGKILL
, false);
580 app_ptr
->state
= LADISH_APP_STATE_KILL
;
583 void ladish_app_save_L1(ladish_app_handle app_handle
)
585 ladish_app_save_L1_internal(app_ptr
);
588 void ladish_app_add_pid(ladish_app_handle app_handle
, pid_t pid
)
590 if (app_ptr
->pid
== 0)
592 log_error("Associating pid with stopped app does not make sense");
597 if (pid
<= 1) /* catch -1, 0 and 1 */
599 log_error("Refusing domination by ignoring pid %d", (int)pid
);
604 if (app_ptr
->pid
== pid
)
605 { /* The top level process that is already known */
609 if (app_ptr
->firstborn_pid
!= 0)
610 { /* Ignore non-first children */
614 log_info("First grandchild with pid %u", (unsigned int)pid
);
615 app_ptr
->firstborn_pid
= pid
;
618 void ladish_app_del_pid(ladish_app_handle app_handle
, pid_t pid
)
620 if (app_ptr
->firstborn_pid
!= 0 && app_ptr
->firstborn_pid
== pid
)
622 log_info("First grandchild with pid %u has gone", (unsigned int)pid
);
623 app_ptr
->firstborn_pid
= 0;
629 void ladish_app_supervisor_autorun(ladish_app_supervisor_handle supervisor_handle
)
631 struct list_head
* node_ptr
;
632 struct ladish_app
* app_ptr
;
634 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
636 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
638 if (!app_ptr
->autorun
)
643 app_ptr
->autorun
= false;
645 log_info("autorun('%s', %s, '%s') called", app_ptr
->name
, app_ptr
->terminal
? "terminal" : "shell", app_ptr
->commandline
);
647 if (!ladish_app_supervisor_start_app((ladish_app_supervisor_handle
)supervisor_ptr
, (ladish_app_handle
)app_ptr
))
649 log_error("Execution of '%s' failed", app_ptr
->commandline
);
655 void ladish_app_supervisor_stop(ladish_app_supervisor_handle supervisor_handle
)
657 struct list_head
* node_ptr
;
658 struct ladish_app
* app_ptr
;
660 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
662 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
663 if (app_ptr
->pid
!= 0)
665 log_info("terminating '%s'...", app_ptr
->name
);
666 ladish_app_send_signal(app_ptr
, SIGTERM
, false);
667 app_ptr
->autorun
= true;
668 app_ptr
->state
= LADISH_APP_STATE_STOPPING
;
673 void ladish_app_supervisor_save_L1(ladish_app_supervisor_handle supervisor_handle
)
675 struct list_head
* node_ptr
;
676 struct ladish_app
* app_ptr
;
678 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
680 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
681 if (app_ptr
->state
!= LADISH_APP_STATE_STARTED
)
686 if (app_ptr
->pid
== 0)
692 ladish_app_save_L1_internal(app_ptr
);
696 const char * ladish_app_supervisor_get_name(ladish_app_supervisor_handle supervisor_handle
)
698 return supervisor_ptr
->name
;
701 unsigned int ladish_app_supervisor_get_running_app_count(ladish_app_supervisor_handle supervisor_handle
)
703 struct list_head
* node_ptr
;
704 struct ladish_app
* app_ptr
;
705 unsigned int counter
;
708 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
710 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
711 if (app_ptr
->pid
!= 0)
720 bool ladish_app_supervisor_has_apps(ladish_app_supervisor_handle supervisor_handle
)
722 return !list_empty(&supervisor_ptr
->applist
);
725 #undef supervisor_ptr
727 /**********************************************************************************/
729 /**********************************************************************************/
731 #define supervisor_ptr ((struct ladish_app_supervisor *)call_ptr->iface_context)
733 static void get_all(struct dbus_method_call
* call_ptr
)
735 DBusMessageIter iter
, array_iter
, struct_iter
;
736 struct list_head
* node_ptr
;
737 struct ladish_app
* app_ptr
;
739 dbus_bool_t terminal
;
741 //log_info("get_all called");
743 call_ptr
->reply
= dbus_message_new_method_return(call_ptr
->message
);
744 if (call_ptr
->reply
== NULL
)
749 dbus_message_iter_init_append(call_ptr
->reply
, &iter
);
751 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_UINT64
, &supervisor_ptr
->version
))
756 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(tsbby)", &array_iter
))
761 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
763 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
765 log_info("app '%s' (%llu)", app_ptr
->name
, (unsigned long long)app_ptr
->id
);
767 if (!dbus_message_iter_open_container (&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
))
772 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT64
, &app_ptr
->id
))
777 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_STRING
, &app_ptr
->name
))
782 running
= app_ptr
->pid
!= 0;
783 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_BOOLEAN
, &running
))
788 terminal
= app_ptr
->terminal
;
789 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_BOOLEAN
, &terminal
))
794 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_BYTE
, &app_ptr
->level
))
799 if (!dbus_message_iter_close_container(&array_iter
, &struct_iter
))
805 if (!dbus_message_iter_close_container(&iter
, &array_iter
))
813 dbus_message_unref(call_ptr
->reply
);
814 call_ptr
->reply
= NULL
;
817 log_error("Ran out of memory trying to construct method return");
820 static void run_custom(struct dbus_method_call
* call_ptr
)
822 dbus_bool_t terminal
;
823 const char * commandline
;
827 if (!dbus_message_get_args(
830 DBUS_TYPE_BOOLEAN
, &terminal
,
831 DBUS_TYPE_STRING
, &commandline
,
832 DBUS_TYPE_STRING
, &name
,
833 DBUS_TYPE_BYTE
, &level
,
836 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
837 dbus_error_free(&g_dbus_error
);
841 log_info("run_custom('%s', %s, '%s', %"PRIu8
") called", name
, terminal
? "terminal" : "shell", commandline
, level
);
843 if (level
!= 0 && level
!= 1)
845 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "invalid level %"PRIu8
, level
);
849 if (ladish_command_new_app(
851 ladish_studio_get_cmd_queue(),
852 supervisor_ptr
->opath
,
858 method_return_new_void(call_ptr
);
862 static void start_app(struct dbus_method_call
* call_ptr
)
866 if (!dbus_message_get_args(
869 DBUS_TYPE_UINT64
, &id
,
872 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
873 dbus_error_free(&g_dbus_error
);
877 if (ladish_command_change_app_state(call_ptr
, ladish_studio_get_cmd_queue(), supervisor_ptr
->opath
, id
, LADISH_APP_STATE_STARTED
))
879 method_return_new_void(call_ptr
);
883 static void stop_app(struct dbus_method_call
* call_ptr
)
887 if (!dbus_message_get_args(
890 DBUS_TYPE_UINT64
, &id
,
893 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
894 dbus_error_free(&g_dbus_error
);
898 if (ladish_command_change_app_state(call_ptr
, ladish_studio_get_cmd_queue(), supervisor_ptr
->opath
, id
, LADISH_APP_STATE_STOPPED
))
900 method_return_new_void(call_ptr
);
904 static void kill_app(struct dbus_method_call
* call_ptr
)
908 if (!dbus_message_get_args(
911 DBUS_TYPE_UINT64
, &id
,
914 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
915 dbus_error_free(&g_dbus_error
);
919 if (ladish_command_change_app_state(call_ptr
, ladish_studio_get_cmd_queue(), supervisor_ptr
->opath
, id
, LADISH_APP_STATE_KILL
))
921 method_return_new_void(call_ptr
);
925 static void get_app_properties(struct dbus_method_call
* call_ptr
)
928 struct ladish_app
* app_ptr
;
930 dbus_bool_t terminal
;
932 if (!dbus_message_get_args(
935 DBUS_TYPE_UINT64
, &id
,
938 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
939 dbus_error_free(&g_dbus_error
);
943 app_ptr
= ladish_app_supervisor_find_app_by_id_internal(supervisor_ptr
, id
);
946 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "App with ID %"PRIu64
" not found", id
);
950 running
= app_ptr
->pid
!= 0;
951 terminal
= app_ptr
->terminal
;
953 call_ptr
->reply
= dbus_message_new_method_return(call_ptr
->message
);
954 if (call_ptr
->reply
== NULL
)
959 if (!dbus_message_append_args(
961 DBUS_TYPE_STRING
, &app_ptr
->name
,
962 DBUS_TYPE_STRING
, &app_ptr
->commandline
,
963 DBUS_TYPE_BOOLEAN
, &running
,
964 DBUS_TYPE_BOOLEAN
, &terminal
,
965 DBUS_TYPE_BYTE
, &app_ptr
->level
,
974 dbus_message_unref(call_ptr
->reply
);
975 call_ptr
->reply
= NULL
;
978 log_error("Ran out of memory trying to construct method return");
981 static void set_app_properties(struct dbus_method_call
* call_ptr
)
984 dbus_bool_t terminal
;
986 const char * commandline
;
988 struct ladish_app
* app_ptr
;
990 char * commandline_buffer
;
992 if (!dbus_message_get_args(
995 DBUS_TYPE_UINT64
, &id
,
996 DBUS_TYPE_STRING
, &name
,
997 DBUS_TYPE_STRING
, &commandline
,
998 DBUS_TYPE_BOOLEAN
, &terminal
,
999 DBUS_TYPE_BYTE
, &level
,
1002 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
1003 dbus_error_free(&g_dbus_error
);
1007 app_ptr
= ladish_app_supervisor_find_app_by_id_internal(supervisor_ptr
, id
);
1008 if (app_ptr
== NULL
)
1010 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "App with ID %"PRIu64
" not found", id
);
1014 if (app_ptr
->pid
!= 0 && strcmp(commandline
, app_ptr
->commandline
) != 0)
1016 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Cannot change commandline when app is running. '%s' -> '%s'", app_ptr
->commandline
, commandline
);
1020 if (app_ptr
->pid
!= 0 && ((app_ptr
->terminal
&& !terminal
) || (!app_ptr
->terminal
&& terminal
)))
1022 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Cannot change whether to run in terminal when app is running");
1026 if (app_ptr
->pid
!= 0 && app_ptr
->level
!= level
)
1028 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Cannot change app level when app is running");
1032 if (strcmp(commandline
, app_ptr
->commandline
) != 0)
1034 commandline_buffer
= strdup(commandline
);
1035 if (commandline_buffer
== NULL
)
1037 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "strdup() failed for app commandline");
1043 commandline_buffer
= NULL
;
1046 if (strcmp(name
, app_ptr
->name
) != 0)
1048 name_buffer
= strdup(name
);
1049 if (name_buffer
== NULL
)
1051 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "strdup() failed for app nam");
1052 if (commandline_buffer
!= NULL
)
1054 free(commandline_buffer
);
1064 if (name_buffer
!= NULL
)
1066 supervisor_ptr
->on_app_renamed(supervisor_ptr
->on_app_renamed_context
, app_ptr
->uuid
, app_ptr
->name
, name_buffer
);
1067 free(app_ptr
->name
);
1068 app_ptr
->name
= name_buffer
;
1071 if (commandline_buffer
!= NULL
)
1073 free(app_ptr
->commandline
);
1074 app_ptr
->commandline
= commandline_buffer
;
1077 app_ptr
->level
= level
;
1078 app_ptr
->terminal
= terminal
;
1080 emit_app_state_changed(supervisor_ptr
, app_ptr
);
1082 method_return_new_void(call_ptr
);
1085 static void remove_app(struct dbus_method_call
* call_ptr
)
1089 if (!dbus_message_get_args(
1092 DBUS_TYPE_UINT64
, &id
,
1095 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
1096 dbus_error_free(&g_dbus_error
);
1100 if (ladish_command_remove_app(call_ptr
, ladish_studio_get_cmd_queue(), supervisor_ptr
->opath
, id
))
1102 method_return_new_void(call_ptr
);
1106 static void is_app_running(struct dbus_method_call
* call_ptr
)
1109 struct ladish_app
* app_ptr
;
1110 dbus_bool_t running
;
1112 if (!dbus_message_get_args(
1115 DBUS_TYPE_UINT64
, &id
,
1118 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
1119 dbus_error_free(&g_dbus_error
);
1123 app_ptr
= ladish_app_supervisor_find_app_by_id_internal(supervisor_ptr
, id
);
1124 if (app_ptr
== NULL
)
1126 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "App with ID %"PRIu64
" not found", id
);
1130 running
= app_ptr
->pid
!= 0;
1132 method_return_new_single(call_ptr
, DBUS_TYPE_BOOLEAN
, &running
);
1135 #undef supervisor_ptr
1137 METHOD_ARGS_BEGIN(GetAll
, "Get list of apps")
1138 METHOD_ARG_DESCRIBE_OUT("list_version", DBUS_TYPE_UINT64_AS_STRING
, "Version of the list")
1139 METHOD_ARG_DESCRIBE_OUT("apps_list", "a(tsbby)", "List of apps")
1142 METHOD_ARGS_BEGIN(RunCustom
, "Start application by supplying commandline")
1143 METHOD_ARG_DESCRIBE_IN("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1144 METHOD_ARG_DESCRIBE_IN("commandline", DBUS_TYPE_STRING_AS_STRING
, "Commandline")
1145 METHOD_ARG_DESCRIBE_IN("name", DBUS_TYPE_STRING_AS_STRING
, "Name")
1146 METHOD_ARG_DESCRIBE_IN("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1149 METHOD_ARGS_BEGIN(StartApp
, "Start application")
1150 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1153 METHOD_ARGS_BEGIN(StopApp
, "Stop application")
1154 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1157 METHOD_ARGS_BEGIN(KillApp
, "Kill application")
1158 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1161 METHOD_ARGS_BEGIN(RemoveApp
, "Remove application")
1162 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1165 METHOD_ARGS_BEGIN(GetAppProperties
, "Get properties of an application")
1166 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1167 METHOD_ARG_DESCRIBE_OUT("name", DBUS_TYPE_STRING_AS_STRING
, "")
1168 METHOD_ARG_DESCRIBE_OUT("commandline", DBUS_TYPE_STRING_AS_STRING
, "Commandline")
1169 METHOD_ARG_DESCRIBE_OUT("running", DBUS_TYPE_BOOLEAN_AS_STRING
, "")
1170 METHOD_ARG_DESCRIBE_OUT("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1171 METHOD_ARG_DESCRIBE_OUT("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1174 METHOD_ARGS_BEGIN(SetAppProperties
, "Set properties of an application")
1175 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1176 METHOD_ARG_DESCRIBE_IN("name", DBUS_TYPE_STRING_AS_STRING
, "")
1177 METHOD_ARG_DESCRIBE_IN("commandline", DBUS_TYPE_STRING_AS_STRING
, "Commandline")
1178 METHOD_ARG_DESCRIBE_IN("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1179 METHOD_ARG_DESCRIBE_IN("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1182 METHOD_ARGS_BEGIN(IsAppRunning
, "Check whether application is running")
1183 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1184 METHOD_ARG_DESCRIBE_OUT("running", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether app is running")
1189 METHOD_DESCRIBE(GetAll
, get_all
) /* sync */
1190 METHOD_DESCRIBE(RunCustom
, run_custom
) /* async */
1191 METHOD_DESCRIBE(StartApp
, start_app
) /* async */
1192 METHOD_DESCRIBE(StopApp
, stop_app
) /* async */
1193 METHOD_DESCRIBE(KillApp
, kill_app
) /* async */
1194 METHOD_DESCRIBE(GetAppProperties
, get_app_properties
) /* sync */
1195 METHOD_DESCRIBE(SetAppProperties
, set_app_properties
) /* sync */
1196 METHOD_DESCRIBE(RemoveApp
, remove_app
) /* sync */
1197 METHOD_DESCRIBE(IsAppRunning
, is_app_running
) /* sync */
1200 SIGNAL_ARGS_BEGIN(AppAdded
, "")
1201 SIGNAL_ARG_DESCRIBE("new_list_version", DBUS_TYPE_UINT64_AS_STRING
, "")
1202 SIGNAL_ARG_DESCRIBE("id", DBUS_TYPE_UINT64_AS_STRING
, "")
1203 SIGNAL_ARG_DESCRIBE("name", DBUS_TYPE_STRING_AS_STRING
, "")
1204 SIGNAL_ARG_DESCRIBE("running", DBUS_TYPE_BOOLEAN_AS_STRING
, "")
1205 SIGNAL_ARG_DESCRIBE("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1206 SIGNAL_ARG_DESCRIBE("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1209 SIGNAL_ARGS_BEGIN(AppRemoved
, "")
1210 SIGNAL_ARG_DESCRIBE("new_list_version", DBUS_TYPE_UINT64_AS_STRING
, "")
1211 SIGNAL_ARG_DESCRIBE("id", DBUS_TYPE_UINT64_AS_STRING
, "")
1214 SIGNAL_ARGS_BEGIN(AppStateChanged
, "")
1215 SIGNAL_ARG_DESCRIBE("new_list_version", DBUS_TYPE_UINT64_AS_STRING
, "")
1216 SIGNAL_ARG_DESCRIBE("id", DBUS_TYPE_UINT64_AS_STRING
, "")
1217 SIGNAL_ARG_DESCRIBE("name", DBUS_TYPE_STRING_AS_STRING
, "")
1218 SIGNAL_ARG_DESCRIBE("running", DBUS_TYPE_BOOLEAN_AS_STRING
, "")
1219 SIGNAL_ARG_DESCRIBE("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1220 SIGNAL_ARG_DESCRIBE("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1224 SIGNAL_DESCRIBE(AppAdded
)
1225 SIGNAL_DESCRIBE(AppRemoved
)
1226 SIGNAL_DESCRIBE(AppStateChanged
)
1229 INTERFACE_BEGIN(g_iface_app_supervisor
, IFACE_APP_SUPERVISOR
)
1230 INTERFACE_DEFAULT_HANDLER
1231 INTERFACE_EXPOSE_METHODS
1232 INTERFACE_EXPOSE_SIGNALS