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>
33 #include "app_supervisor.h"
34 #include "../dbus/error.h"
35 #include "../dbus_constants.h"
37 #include "studio_internal.h"
38 #include "../proxies/notify_proxy.h"
42 struct list_head siblings
;
53 bool zombie
; /* if true, remove when stopped */
58 struct ladish_app_supervisor
66 struct list_head applist
;
67 void * on_app_renamed_context
;
68 ladish_app_supervisor_on_app_renamed_callback on_app_renamed
;
72 ladish_app_supervisor_create(
73 ladish_app_supervisor_handle
* supervisor_handle_ptr
,
77 ladish_app_supervisor_on_app_renamed_callback on_app_renamed
)
79 struct ladish_app_supervisor
* supervisor_ptr
;
81 supervisor_ptr
= malloc(sizeof(struct ladish_app_supervisor
));
82 if (supervisor_ptr
== NULL
)
84 log_error("malloc() failed to allocate struct ladish_app_supervisor");
88 supervisor_ptr
->opath
= strdup(opath
);
89 if (supervisor_ptr
->opath
== NULL
)
91 log_error("strdup() failed for app supervisor opath");
96 supervisor_ptr
->name
= strdup(name
);
97 if (supervisor_ptr
->name
== NULL
)
99 log_error("strdup() failed for app supervisor name");
100 free(supervisor_ptr
->opath
);
101 free(supervisor_ptr
);
105 supervisor_ptr
->dir
= NULL
;
106 supervisor_ptr
->project_name
= NULL
;
108 supervisor_ptr
->version
= 0;
109 supervisor_ptr
->next_id
= 1;
111 INIT_LIST_HEAD(&supervisor_ptr
->applist
);
113 supervisor_ptr
->on_app_renamed_context
= context
;
114 supervisor_ptr
->on_app_renamed
= on_app_renamed
;
116 *supervisor_handle_ptr
= (ladish_app_supervisor_handle
)supervisor_ptr
;
121 struct ladish_app
* ladish_app_supervisor_find_app_by_id_internal(struct ladish_app_supervisor
* supervisor_ptr
, uint64_t id
)
123 struct list_head
* node_ptr
;
124 struct ladish_app
* app_ptr
;
126 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
128 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
129 if (app_ptr
->id
== id
)
138 void remove_app_internal(struct ladish_app_supervisor
* supervisor_ptr
, struct ladish_app
* app_ptr
)
140 ASSERT(app_ptr
->pid
== 0); /* Removing not-stoped app? Zombies will make a rebellion! */
142 list_del(&app_ptr
->siblings
);
144 supervisor_ptr
->version
++;
148 supervisor_ptr
->opath
,
149 IFACE_APP_SUPERVISOR
,
152 &supervisor_ptr
->version
,
156 free(app_ptr
->commandline
);
160 void emit_app_state_changed(struct ladish_app_supervisor
* supervisor_ptr
, struct ladish_app
* app_ptr
)
163 dbus_bool_t terminal
;
165 running
= app_ptr
->pid
!= 0;
166 terminal
= app_ptr
->terminal
;
168 supervisor_ptr
->version
++;
172 supervisor_ptr
->opath
,
173 IFACE_APP_SUPERVISOR
,
176 &supervisor_ptr
->version
,
184 #define supervisor_ptr ((struct ladish_app_supervisor *)supervisor_handle)
186 const char * ladish_app_supervisor_get_opath(ladish_app_supervisor_handle supervisor_handle
)
188 return supervisor_ptr
->opath
;
191 ladish_app_handle
ladish_app_supervisor_find_app_by_name(ladish_app_supervisor_handle supervisor_handle
, const char * name
)
193 struct list_head
* node_ptr
;
194 struct ladish_app
* app_ptr
;
196 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
198 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
199 if (strcmp(app_ptr
->name
, name
) == 0)
201 return (ladish_app_handle
)app_ptr
;
208 ladish_app_handle
ladish_app_supervisor_find_app_by_id(ladish_app_supervisor_handle supervisor_handle
, uint64_t id
)
210 return (ladish_app_handle
)ladish_app_supervisor_find_app_by_id_internal(supervisor_ptr
, id
);
213 ladish_app_handle
ladish_app_supervisor_find_app_by_pid(ladish_app_supervisor_handle supervisor_handle
, pid_t pid
)
215 struct list_head
* node_ptr
;
216 struct ladish_app
* app_ptr
;
218 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
220 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
221 if (app_ptr
->pid
== pid
)
223 //log_info("app \"%s\" found by pid %llu", app_ptr->name, (unsigned long long)pid);
224 return (ladish_app_handle
)app_ptr
;
231 ladish_app_handle
ladish_app_supervisor_find_app_by_uuid(ladish_app_supervisor_handle supervisor_handle
, const uuid_t uuid
)
233 struct list_head
* node_ptr
;
234 struct ladish_app
* app_ptr
;
236 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
238 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
239 if (uuid_compare(app_ptr
->uuid
, uuid
) == 0)
241 return (ladish_app_handle
)app_ptr
;
249 ladish_app_supervisor_add(
250 ladish_app_supervisor_handle supervisor_handle
,
254 const char * command
,
258 struct ladish_app
* app_ptr
;
261 app_ptr
= malloc(sizeof(struct ladish_app
));
264 log_error("malloc of struct ladish_app failed");
268 app_ptr
->name
= strdup(name
);
269 if (app_ptr
->name
== NULL
)
271 log_error("strdup() failed for app name");
276 app_ptr
->commandline
= strdup(command
);
277 if (app_ptr
->commandline
== NULL
)
279 log_error("strdup() failed for app commandline");
285 app_ptr
->terminal
= terminal
;
286 app_ptr
->level
= level
;
289 app_ptr
->firstborn_pid
= 0;
290 app_ptr
->firstborn_pgrp
= 0;
292 app_ptr
->id
= supervisor_ptr
->next_id
++;
293 if (uuid
== NULL
|| uuid_is_null(uuid
))
295 uuid_generate(app_ptr
->uuid
);
299 uuid_copy(app_ptr
->uuid
, uuid
);
302 app_ptr
->zombie
= false;
303 app_ptr
->state
= LADISH_APP_STATE_STOPPED
;
304 app_ptr
->autorun
= autorun
;
305 list_add_tail(&app_ptr
->siblings
, &supervisor_ptr
->applist
);
307 supervisor_ptr
->version
++;
312 supervisor_ptr
->opath
,
313 IFACE_APP_SUPERVISOR
,
316 &supervisor_ptr
->version
,
323 return (ladish_app_handle
)app_ptr
;
326 static void ladish_app_send_signal(struct ladish_app
* app_ptr
, int sig
, bool prefer_firstborn
)
329 const char * signal_name
;
331 ASSERT(app_ptr
->state
= LADISH_APP_STATE_STARTED
);
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";
356 if (app_ptr
->pgrp
== 0)
358 app_ptr
->pgrp
= getpgid(app_ptr
->pid
);
359 if (app_ptr
->pgrp
== -1)
364 log_error("getpgid(%u) failed. %s (%d)", (unsigned int)app_ptr
->pid
, strerror(errno
), errno
);
369 if (app_ptr
->firstborn_pid
!= 0)
371 app_ptr
->firstborn_pgrp
= getpgid(app_ptr
->firstborn_pid
);
372 if (app_ptr
->firstborn_pgrp
== -1)
374 app_ptr
->firstborn_pgrp
= 0;
377 log_error("getpgid(%u) failed (firstborn). %s (%d)", (unsigned int)app_ptr
->firstborn_pid
, strerror(errno
), errno
);
382 if (app_ptr
->pgrp
!= 0)
384 log_info("sending signal %d (%s) to pgrp %u ('%s')", sig
, signal_name
, (unsigned int)app_ptr
->pgrp
, app_ptr
->name
);
386 if (app_ptr
->pgrp
<= 1)
392 killpg(app_ptr
->pgrp
, sig
);
394 if (app_ptr
->firstborn_pid
!= 0)
396 if (app_ptr
->firstborn_pgrp
!= 0)
398 if (app_ptr
->firstborn_pgrp
<= 1)
404 if (app_ptr
->firstborn_pgrp
!= app_ptr
->pgrp
)
406 log_info("sending signal %d (%s) to firstborn pgrp %u ('%s')", sig
, signal_name
, (unsigned int)app_ptr
->firstborn_pgrp
, app_ptr
->name
);
408 killpg(app_ptr
->firstborn_pgrp
, sig
);
412 /* fall through to sending signal to pid */
419 /* fall through to sending signal to pid */
421 if (app_ptr
->pid
<= 1)
427 if (prefer_firstborn
&& app_ptr
->firstborn_pid
!= 0)
429 pid
= app_ptr
->firstborn_pid
;
442 log_info("sending signal %d (%s) to '%s' with pid %u", sig
, signal_name
, app_ptr
->name
, (unsigned int)pid
);
447 bool ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle
)
449 struct list_head
* node_ptr
;
450 struct list_head
* safe_node_ptr
;
451 struct ladish_app
* app_ptr
;
454 free(supervisor_ptr
->dir
);
455 supervisor_ptr
->dir
= NULL
;
457 free(supervisor_ptr
->project_name
);
458 supervisor_ptr
->project_name
= NULL
;
462 list_for_each_safe(node_ptr
, safe_node_ptr
, &supervisor_ptr
->applist
)
464 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
465 if (app_ptr
->pid
!= 0)
467 log_info("terminating '%s'...", app_ptr
->name
);
468 ladish_app_send_signal(app_ptr
, SIGTERM
, false);
469 app_ptr
->zombie
= true;
470 app_ptr
->state
= LADISH_APP_STATE_STOPPING
;
475 log_info("removing '%s'", app_ptr
->name
);
476 remove_app_internal(supervisor_ptr
, app_ptr
);
483 void ladish_app_supervisor_destroy(ladish_app_supervisor_handle supervisor_handle
)
485 ladish_app_supervisor_clear(supervisor_handle
);
486 free(supervisor_ptr
->name
);
487 free(supervisor_ptr
->opath
);
488 free(supervisor_ptr
);
492 ladish_app_supervisor_set_directory(
493 ladish_app_supervisor_handle supervisor_handle
,
501 log_error("strdup(\"%s\") failed", dir
);
505 if (supervisor_ptr
->dir
!= NULL
)
507 free(supervisor_ptr
->dir
);
510 supervisor_ptr
->dir
= dup
;
516 ladish_app_supervisor_set_project_name(
517 ladish_app_supervisor_handle supervisor_handle
,
518 const char * project_name
)
522 if (project_name
!= NULL
)
524 dup
= strdup(project_name
);
527 log_error("strdup(\"%s\") failed", project_name
);
536 free(supervisor_ptr
->project_name
);
537 supervisor_ptr
->project_name
= dup
;
542 bool ladish_app_supervisor_child_exit(ladish_app_supervisor_handle supervisor_handle
, pid_t pid
)
544 struct list_head
* node_ptr
;
545 struct ladish_app
* app_ptr
;
547 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
549 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
550 if (app_ptr
->pid
== pid
)
552 log_info("exit of child '%s' detected.", app_ptr
->name
);
556 app_ptr
->firstborn_pid
= 0;
557 app_ptr
->firstborn_pgrp
= 0;
560 remove_app_internal(supervisor_ptr
, app_ptr
);
564 if (app_ptr
->state
== LADISH_APP_STATE_STARTED
)
566 ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH
, "App terminated unexpectedly", app_ptr
->name
);
569 app_ptr
->state
= LADISH_APP_STATE_STOPPED
;
571 emit_app_state_changed(supervisor_ptr
, app_ptr
);
582 ladish_app_supervisor_enum(
583 ladish_app_supervisor_handle supervisor_handle
,
585 ladish_app_supervisor_enum_callback callback
)
587 struct list_head
* node_ptr
;
588 struct ladish_app
* app_ptr
;
590 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
592 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
594 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
))
603 static inline void ladish_app_save_L1_internal(struct ladish_app
* app_ptr
)
605 if (app_ptr
->level
== 1)
607 ladish_app_send_signal(app_ptr
, SIGUSR1
, true);
611 #define app_ptr ((struct ladish_app *)app_handle)
613 bool ladish_app_supervisor_start_app(ladish_app_supervisor_handle supervisor_handle
, ladish_app_handle app_handle
)
615 app_ptr
->zombie
= false;
617 ASSERT(app_ptr
->pid
== 0);
620 supervisor_ptr
->name
,
621 supervisor_ptr
->project_name
,
623 supervisor_ptr
->dir
!= NULL
? supervisor_ptr
->dir
: "/",
625 app_ptr
->commandline
,
631 ASSERT(app_ptr
->pid
!= 0);
632 app_ptr
->state
= LADISH_APP_STATE_STARTED
;
634 emit_app_state_changed(supervisor_ptr
, app_ptr
);
638 void ladish_app_supervisor_remove_app(ladish_app_supervisor_handle supervisor_handle
, ladish_app_handle app_handle
)
640 remove_app_internal(supervisor_ptr
, app_ptr
);
643 unsigned int ladish_app_get_state(ladish_app_handle app_handle
)
645 return app_ptr
->state
;
648 bool ladish_app_is_running(ladish_app_handle app_handle
)
650 return app_ptr
->pid
!= 0;
653 const char * ladish_app_get_name(ladish_app_handle app_handle
)
655 return app_ptr
->name
;
658 void ladish_app_get_uuid(ladish_app_handle app_handle
, uuid_t uuid
)
660 uuid_copy(uuid
, app_ptr
->uuid
);
663 void ladish_app_stop(ladish_app_handle app_handle
)
665 ladish_app_send_signal(app_ptr
, SIGTERM
, false);
666 app_ptr
->state
= LADISH_APP_STATE_STOPPING
;
669 void ladish_app_kill(ladish_app_handle app_handle
)
671 ladish_app_send_signal(app_ptr
, SIGKILL
, false);
672 app_ptr
->state
= LADISH_APP_STATE_KILL
;
675 void ladish_app_save_L1(ladish_app_handle app_handle
)
677 ladish_app_save_L1_internal(app_ptr
);
680 void ladish_app_add_pid(ladish_app_handle app_handle
, pid_t pid
)
682 if (app_ptr
->pid
== 0)
684 log_error("Associating pid with stopped app does not make sense");
689 if (pid
<= 1) /* catch -1, 0 and 1 */
691 log_error("Refusing domination by ignoring pid %d", (int)pid
);
696 if (app_ptr
->pid
== pid
)
697 { /* The top level process that is already known */
701 if (app_ptr
->firstborn_pid
!= 0)
702 { /* Ignore non-first children */
706 log_info("First grandchild with pid %u", (unsigned int)pid
);
707 app_ptr
->firstborn_pid
= pid
;
710 void ladish_app_del_pid(ladish_app_handle app_handle
, pid_t pid
)
712 if (app_ptr
->firstborn_pid
!= 0 && app_ptr
->firstborn_pid
== pid
)
714 log_info("First grandchild with pid %u has gone", (unsigned int)pid
);
715 app_ptr
->firstborn_pid
= 0;
716 app_ptr
->firstborn_pgrp
= 0;
722 void ladish_app_supervisor_autorun(ladish_app_supervisor_handle supervisor_handle
)
724 struct list_head
* node_ptr
;
725 struct ladish_app
* app_ptr
;
727 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
729 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
731 if (!app_ptr
->autorun
)
736 app_ptr
->autorun
= false;
738 log_info("autorun('%s', %s, '%s') called", app_ptr
->name
, app_ptr
->terminal
? "terminal" : "shell", app_ptr
->commandline
);
740 if (!ladish_app_supervisor_start_app((ladish_app_supervisor_handle
)supervisor_ptr
, (ladish_app_handle
)app_ptr
))
742 log_error("Execution of '%s' failed", app_ptr
->commandline
);
748 void ladish_app_supervisor_stop(ladish_app_supervisor_handle supervisor_handle
)
750 struct list_head
* node_ptr
;
751 struct ladish_app
* app_ptr
;
753 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
755 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
756 if (app_ptr
->pid
!= 0)
758 log_info("terminating '%s'...", app_ptr
->name
);
759 ladish_app_send_signal(app_ptr
, SIGTERM
, false);
760 app_ptr
->autorun
= true;
761 app_ptr
->state
= LADISH_APP_STATE_STOPPING
;
766 void ladish_app_supervisor_save_L1(ladish_app_supervisor_handle supervisor_handle
)
768 struct list_head
* node_ptr
;
769 struct ladish_app
* app_ptr
;
771 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
773 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
774 if (app_ptr
->state
!= LADISH_APP_STATE_STARTED
)
779 if (app_ptr
->pid
== 0)
785 ladish_app_save_L1_internal(app_ptr
);
789 const char * ladish_app_supervisor_get_name(ladish_app_supervisor_handle supervisor_handle
)
791 return supervisor_ptr
->name
;
794 unsigned int ladish_app_supervisor_get_running_app_count(ladish_app_supervisor_handle supervisor_handle
)
796 struct list_head
* node_ptr
;
797 struct ladish_app
* app_ptr
;
798 unsigned int counter
;
801 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
803 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
804 if (app_ptr
->pid
!= 0)
813 bool ladish_app_supervisor_has_apps(ladish_app_supervisor_handle supervisor_handle
)
815 return !list_empty(&supervisor_ptr
->applist
);
818 #undef supervisor_ptr
820 /**********************************************************************************/
822 /**********************************************************************************/
824 #define supervisor_ptr ((struct ladish_app_supervisor *)call_ptr->iface_context)
826 static void get_all(struct dbus_method_call
* call_ptr
)
828 DBusMessageIter iter
, array_iter
, struct_iter
;
829 struct list_head
* node_ptr
;
830 struct ladish_app
* app_ptr
;
832 dbus_bool_t terminal
;
834 //log_info("get_all called");
836 call_ptr
->reply
= dbus_message_new_method_return(call_ptr
->message
);
837 if (call_ptr
->reply
== NULL
)
842 dbus_message_iter_init_append(call_ptr
->reply
, &iter
);
844 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_UINT64
, &supervisor_ptr
->version
))
849 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(tsbby)", &array_iter
))
854 list_for_each(node_ptr
, &supervisor_ptr
->applist
)
856 app_ptr
= list_entry(node_ptr
, struct ladish_app
, siblings
);
858 log_info("app '%s' (%llu)", app_ptr
->name
, (unsigned long long)app_ptr
->id
);
860 if (!dbus_message_iter_open_container (&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
))
865 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT64
, &app_ptr
->id
))
870 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_STRING
, &app_ptr
->name
))
875 running
= app_ptr
->pid
!= 0;
876 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_BOOLEAN
, &running
))
881 terminal
= app_ptr
->terminal
;
882 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_BOOLEAN
, &terminal
))
887 if (!dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_BYTE
, &app_ptr
->level
))
892 if (!dbus_message_iter_close_container(&array_iter
, &struct_iter
))
898 if (!dbus_message_iter_close_container(&iter
, &array_iter
))
906 dbus_message_unref(call_ptr
->reply
);
907 call_ptr
->reply
= NULL
;
910 log_error("Ran out of memory trying to construct method return");
913 static void run_custom(struct dbus_method_call
* call_ptr
)
915 dbus_bool_t terminal
;
916 const char * commandline
;
920 if (!dbus_message_get_args(
923 DBUS_TYPE_BOOLEAN
, &terminal
,
924 DBUS_TYPE_STRING
, &commandline
,
925 DBUS_TYPE_STRING
, &name
,
926 DBUS_TYPE_BYTE
, &level
,
929 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
930 dbus_error_free(&g_dbus_error
);
934 log_info("run_custom('%s', %s, '%s', %"PRIu8
") called", name
, terminal
? "terminal" : "shell", commandline
, level
);
936 if (level
!= 0 && level
!= 1)
938 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "invalid level %"PRIu8
, level
);
942 if (ladish_command_new_app(
944 ladish_studio_get_cmd_queue(),
945 supervisor_ptr
->opath
,
951 method_return_new_void(call_ptr
);
955 static void start_app(struct dbus_method_call
* call_ptr
)
959 if (!dbus_message_get_args(
962 DBUS_TYPE_UINT64
, &id
,
965 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
966 dbus_error_free(&g_dbus_error
);
970 if (ladish_command_change_app_state(call_ptr
, ladish_studio_get_cmd_queue(), supervisor_ptr
->opath
, id
, LADISH_APP_STATE_STARTED
))
972 method_return_new_void(call_ptr
);
976 static void stop_app(struct dbus_method_call
* call_ptr
)
980 if (!dbus_message_get_args(
983 DBUS_TYPE_UINT64
, &id
,
986 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
987 dbus_error_free(&g_dbus_error
);
991 if (ladish_command_change_app_state(call_ptr
, ladish_studio_get_cmd_queue(), supervisor_ptr
->opath
, id
, LADISH_APP_STATE_STOPPED
))
993 method_return_new_void(call_ptr
);
997 static void kill_app(struct dbus_method_call
* call_ptr
)
1001 if (!dbus_message_get_args(
1004 DBUS_TYPE_UINT64
, &id
,
1007 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
1008 dbus_error_free(&g_dbus_error
);
1012 if (ladish_command_change_app_state(call_ptr
, ladish_studio_get_cmd_queue(), supervisor_ptr
->opath
, id
, LADISH_APP_STATE_KILL
))
1014 method_return_new_void(call_ptr
);
1018 static void get_app_properties(struct dbus_method_call
* call_ptr
)
1021 struct ladish_app
* app_ptr
;
1022 dbus_bool_t running
;
1023 dbus_bool_t terminal
;
1025 if (!dbus_message_get_args(
1028 DBUS_TYPE_UINT64
, &id
,
1031 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
1032 dbus_error_free(&g_dbus_error
);
1036 app_ptr
= ladish_app_supervisor_find_app_by_id_internal(supervisor_ptr
, id
);
1037 if (app_ptr
== NULL
)
1039 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "App with ID %"PRIu64
" not found", id
);
1043 running
= app_ptr
->pid
!= 0;
1044 terminal
= app_ptr
->terminal
;
1046 call_ptr
->reply
= dbus_message_new_method_return(call_ptr
->message
);
1047 if (call_ptr
->reply
== NULL
)
1052 if (!dbus_message_append_args(
1054 DBUS_TYPE_STRING
, &app_ptr
->name
,
1055 DBUS_TYPE_STRING
, &app_ptr
->commandline
,
1056 DBUS_TYPE_BOOLEAN
, &running
,
1057 DBUS_TYPE_BOOLEAN
, &terminal
,
1058 DBUS_TYPE_BYTE
, &app_ptr
->level
,
1067 dbus_message_unref(call_ptr
->reply
);
1068 call_ptr
->reply
= NULL
;
1071 log_error("Ran out of memory trying to construct method return");
1074 static void set_app_properties(struct dbus_method_call
* call_ptr
)
1077 dbus_bool_t terminal
;
1079 const char * commandline
;
1081 struct ladish_app
* app_ptr
;
1083 char * commandline_buffer
;
1085 if (!dbus_message_get_args(
1088 DBUS_TYPE_UINT64
, &id
,
1089 DBUS_TYPE_STRING
, &name
,
1090 DBUS_TYPE_STRING
, &commandline
,
1091 DBUS_TYPE_BOOLEAN
, &terminal
,
1092 DBUS_TYPE_BYTE
, &level
,
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 app_ptr
= ladish_app_supervisor_find_app_by_id_internal(supervisor_ptr
, id
);
1101 if (app_ptr
== NULL
)
1103 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "App with ID %"PRIu64
" not found", id
);
1107 if (app_ptr
->pid
!= 0 && strcmp(commandline
, app_ptr
->commandline
) != 0)
1109 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Cannot change commandline when app is running. '%s' -> '%s'", app_ptr
->commandline
, commandline
);
1113 if (app_ptr
->pid
!= 0 && ((app_ptr
->terminal
&& !terminal
) || (!app_ptr
->terminal
&& terminal
)))
1115 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Cannot change whether to run in terminal when app is running");
1119 if (app_ptr
->pid
!= 0 && app_ptr
->level
!= level
)
1121 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Cannot change app level when app is running");
1125 if (strcmp(commandline
, app_ptr
->commandline
) != 0)
1127 commandline_buffer
= strdup(commandline
);
1128 if (commandline_buffer
== NULL
)
1130 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "strdup() failed for app commandline");
1136 commandline_buffer
= NULL
;
1139 if (strcmp(name
, app_ptr
->name
) != 0)
1141 name_buffer
= strdup(name
);
1142 if (name_buffer
== NULL
)
1144 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "strdup() failed for app nam");
1145 if (commandline_buffer
!= NULL
)
1147 free(commandline_buffer
);
1157 if (name_buffer
!= NULL
)
1159 supervisor_ptr
->on_app_renamed(supervisor_ptr
->on_app_renamed_context
, app_ptr
->uuid
, app_ptr
->name
, name_buffer
);
1160 free(app_ptr
->name
);
1161 app_ptr
->name
= name_buffer
;
1164 if (commandline_buffer
!= NULL
)
1166 free(app_ptr
->commandline
);
1167 app_ptr
->commandline
= commandline_buffer
;
1170 app_ptr
->level
= level
;
1171 app_ptr
->terminal
= terminal
;
1173 emit_app_state_changed(supervisor_ptr
, app_ptr
);
1175 method_return_new_void(call_ptr
);
1178 static void remove_app(struct dbus_method_call
* call_ptr
)
1182 if (!dbus_message_get_args(
1185 DBUS_TYPE_UINT64
, &id
,
1188 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
1189 dbus_error_free(&g_dbus_error
);
1193 if (ladish_command_remove_app(call_ptr
, ladish_studio_get_cmd_queue(), supervisor_ptr
->opath
, id
))
1195 method_return_new_void(call_ptr
);
1199 static void is_app_running(struct dbus_method_call
* call_ptr
)
1202 struct ladish_app
* app_ptr
;
1203 dbus_bool_t running
;
1205 if (!dbus_message_get_args(
1208 DBUS_TYPE_UINT64
, &id
,
1211 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, g_dbus_error
.message
);
1212 dbus_error_free(&g_dbus_error
);
1216 app_ptr
= ladish_app_supervisor_find_app_by_id_internal(supervisor_ptr
, id
);
1217 if (app_ptr
== NULL
)
1219 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "App with ID %"PRIu64
" not found", id
);
1223 running
= app_ptr
->pid
!= 0;
1225 method_return_new_single(call_ptr
, DBUS_TYPE_BOOLEAN
, &running
);
1228 #undef supervisor_ptr
1230 METHOD_ARGS_BEGIN(GetAll
, "Get list of apps")
1231 METHOD_ARG_DESCRIBE_OUT("list_version", DBUS_TYPE_UINT64_AS_STRING
, "Version of the list")
1232 METHOD_ARG_DESCRIBE_OUT("apps_list", "a(tsbby)", "List of apps")
1235 METHOD_ARGS_BEGIN(RunCustom
, "Start application by supplying commandline")
1236 METHOD_ARG_DESCRIBE_IN("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1237 METHOD_ARG_DESCRIBE_IN("commandline", DBUS_TYPE_STRING_AS_STRING
, "Commandline")
1238 METHOD_ARG_DESCRIBE_IN("name", DBUS_TYPE_STRING_AS_STRING
, "Name")
1239 METHOD_ARG_DESCRIBE_IN("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1242 METHOD_ARGS_BEGIN(StartApp
, "Start application")
1243 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1246 METHOD_ARGS_BEGIN(StopApp
, "Stop application")
1247 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1250 METHOD_ARGS_BEGIN(KillApp
, "Kill application")
1251 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1254 METHOD_ARGS_BEGIN(RemoveApp
, "Remove application")
1255 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1258 METHOD_ARGS_BEGIN(GetAppProperties
, "Get properties of an application")
1259 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1260 METHOD_ARG_DESCRIBE_OUT("name", DBUS_TYPE_STRING_AS_STRING
, "")
1261 METHOD_ARG_DESCRIBE_OUT("commandline", DBUS_TYPE_STRING_AS_STRING
, "Commandline")
1262 METHOD_ARG_DESCRIBE_OUT("running", DBUS_TYPE_BOOLEAN_AS_STRING
, "")
1263 METHOD_ARG_DESCRIBE_OUT("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1264 METHOD_ARG_DESCRIBE_OUT("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1267 METHOD_ARGS_BEGIN(SetAppProperties
, "Set properties of an application")
1268 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1269 METHOD_ARG_DESCRIBE_IN("name", DBUS_TYPE_STRING_AS_STRING
, "")
1270 METHOD_ARG_DESCRIBE_IN("commandline", DBUS_TYPE_STRING_AS_STRING
, "Commandline")
1271 METHOD_ARG_DESCRIBE_IN("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1272 METHOD_ARG_DESCRIBE_IN("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1275 METHOD_ARGS_BEGIN(IsAppRunning
, "Check whether application is running")
1276 METHOD_ARG_DESCRIBE_IN("id", DBUS_TYPE_UINT64_AS_STRING
, "id of app")
1277 METHOD_ARG_DESCRIBE_OUT("running", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether app is running")
1282 METHOD_DESCRIBE(GetAll
, get_all
) /* sync */
1283 METHOD_DESCRIBE(RunCustom
, run_custom
) /* async */
1284 METHOD_DESCRIBE(StartApp
, start_app
) /* async */
1285 METHOD_DESCRIBE(StopApp
, stop_app
) /* async */
1286 METHOD_DESCRIBE(KillApp
, kill_app
) /* async */
1287 METHOD_DESCRIBE(GetAppProperties
, get_app_properties
) /* sync */
1288 METHOD_DESCRIBE(SetAppProperties
, set_app_properties
) /* sync */
1289 METHOD_DESCRIBE(RemoveApp
, remove_app
) /* sync */
1290 METHOD_DESCRIBE(IsAppRunning
, is_app_running
) /* sync */
1293 SIGNAL_ARGS_BEGIN(AppAdded
, "")
1294 SIGNAL_ARG_DESCRIBE("new_list_version", DBUS_TYPE_UINT64_AS_STRING
, "")
1295 SIGNAL_ARG_DESCRIBE("id", DBUS_TYPE_UINT64_AS_STRING
, "")
1296 SIGNAL_ARG_DESCRIBE("name", DBUS_TYPE_STRING_AS_STRING
, "")
1297 SIGNAL_ARG_DESCRIBE("running", DBUS_TYPE_BOOLEAN_AS_STRING
, "")
1298 SIGNAL_ARG_DESCRIBE("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1299 SIGNAL_ARG_DESCRIBE("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1302 SIGNAL_ARGS_BEGIN(AppRemoved
, "")
1303 SIGNAL_ARG_DESCRIBE("new_list_version", DBUS_TYPE_UINT64_AS_STRING
, "")
1304 SIGNAL_ARG_DESCRIBE("id", DBUS_TYPE_UINT64_AS_STRING
, "")
1307 SIGNAL_ARGS_BEGIN(AppStateChanged
, "")
1308 SIGNAL_ARG_DESCRIBE("new_list_version", DBUS_TYPE_UINT64_AS_STRING
, "")
1309 SIGNAL_ARG_DESCRIBE("id", DBUS_TYPE_UINT64_AS_STRING
, "")
1310 SIGNAL_ARG_DESCRIBE("name", DBUS_TYPE_STRING_AS_STRING
, "")
1311 SIGNAL_ARG_DESCRIBE("running", DBUS_TYPE_BOOLEAN_AS_STRING
, "")
1312 SIGNAL_ARG_DESCRIBE("terminal", DBUS_TYPE_BOOLEAN_AS_STRING
, "Whether to run in terminal")
1313 SIGNAL_ARG_DESCRIBE("level", DBUS_TYPE_BYTE_AS_STRING
, "Level")
1317 SIGNAL_DESCRIBE(AppAdded
)
1318 SIGNAL_DESCRIBE(AppRemoved
)
1319 SIGNAL_DESCRIBE(AppStateChanged
)
1322 INTERFACE_BEGIN(g_iface_app_supervisor
, IFACE_APP_SUPERVISOR
)
1323 INTERFACE_DEFAULT_HANDLER
1324 INTERFACE_EXPOSE_METHODS
1325 INTERFACE_EXPOSE_SIGNALS