From: Hwankyu Jhun Date: Wed, 10 Apr 2019 02:16:29 +0000 (+0900) Subject: Add new functions for retrieving running component context X-Git-Tag: accepted/tizen/unified/20190423.113445~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=061df7d85ffea14d1e790284f731b0767dfa25ae;p=platform%2Fcore%2Fappfw%2Faul-1.git Add new functions for retrieving running component context Adds: - aul_comp_context_foreach() - aul_comp_context_foreach_usr() - aul_comp_context_get_app_id() - aul_comp_context_get_instance_id() - aul_comp_context_get_comp_id() - aul_comp_context_get_type() - aul_comp_context_get_pid() - aul_comp_context_get_status() - aul_comp_context_is_sub_comp() Requires: - https://review.tizen.org/gerrit/#/c/platform/core/appfw/aul-1/+/203105/ - https://review.tizen.org/gerrit/#/c/platform/core/appfw/amd/+/204068/ Change-Id: Ic1757e8ccea42339677ccffe444ca56efc362300 Signed-off-by: Hwankyu Jhun --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 07a1cfe..08ae927 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,7 @@ SET(HEADERS_LIB_AUL aul_comp_status.h aul_app_group.h aul_comp_info.h + aul_comp_context.h ) # Install headers, other files diff --git a/include/aul_cmd.h b/include/aul_cmd.h index 12d93af..dbe6727 100755 --- a/include/aul_cmd.h +++ b/include/aul_cmd.h @@ -150,6 +150,7 @@ enum app_cmd { APP_GROUP_GET_LEADER_IDS = 117, APP_GROUP_GET_GROUP_INFO = 118, APP_GROUP_GET_IDLE_INFO = 119, + COMP_CONTEXT_FOREACH = 120, APP_CMD_MAX }; diff --git a/include/aul_comp_context.h b/include/aul_comp_context.h new file mode 100644 index 0000000..15212ab --- /dev/null +++ b/include/aul_comp_context.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "aul.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The component context handle. + * @since_tizen 5.5 + */ +typedef struct aul_comp_context_s *aul_comp_context_h; + +/** + * @brief Called to get the component context for each component. + * @since_tizen 5.5 + * + * @param[in] handle The component context handle + * @param[in] user_data The user data passed from the foreach function + * @return @c true to continue with the next iteration of the loop, \n + * otherwise @ false to break out of the loop + * @see aul_comp_context_foreach() + */ +typedef void (*aul_comp_context_cb)(aul_comp_context_h handle, void *user_data); + +/** + * @brief Retrieves all running components context. + * @since_tizen 5.5 + * + * @param[in] callback The callback function to invoke + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, + * otherwise a negative error value + * @see aul_comp_context_cb() + * + * @remarks This function is only for App Framework internally. + */ +int aul_comp_context_foreach(aul_comp_context_cb callback, void *user_data); + +/** + * @brief Gets the application ID of the component. + * @since_tizen 5.5 + * @remarks You MUST NOT release @a app_id using free(). + * + * @param[in] handle The component context handle + * @param[out] app_id The application ID of the component + * @return @c 0 on success, + * otherwise a negative error value + * + * @remarks This function is only for App Framework internally. + */ +int aul_comp_context_get_app_id(aul_comp_context_h handle, const char **app_id); + +/** + * @brief Gets the instance ID of the component. + * @since_tizen 5.5 + * @remarks You MUST NOT release @a app_id using free(). + * + * @param[in] handle The component context handle + * @param[out] instance_id The instance ID of the component + * @return @c 0 on success, + * otherwise a negative error value + * + * @remarks This function is only for App Framework internally. + */ +int aul_comp_context_get_instance_id(aul_comp_context_h handle, + const char **instance_id); + +/** + * @brief Gets the ID of the component. + * @since_tizen 5.5 + * @remarks You MUST NOT release @a comp_id using free(). + * + * @param[in] handle The component context handle + * @param[out] comp_id The ID of the component + * @return @c 0 on success, + * otherwise a negative error value + * + * @remarks This function is only for App Framework internally. + */ +int aul_comp_context_get_comp_id(aul_comp_context_h handle, + const char **comp_id); + +/** + * @brief Gets the type of the component. + * @since_tizen 5.5 + * @remarks You MUST NOT release @a type using free(). + * + * @param[in] handle The component context handle + * @param[out] type The type of the component + * @return @c 0 on success, + * otherwise a negative error value + * + * @remarks This function is only for App Framework internally. + */ +int aul_comp_context_get_type(aul_comp_context_h handle, const char **type); + +/** + * @brief Gets the process ID of the component. + * @since_tizen 5.5 + * + * @param[in] handle The component context handle + * @param[out] pid The process ID of the component + * @return @c 0 on success, + * otherwise a negative error value + * + * @remarks This function is only for App Framework internally. + */ +int aul_comp_context_get_pid(aul_comp_context_h handle, pid_t *pid); + +/** + * @brief Gets the status of the component. + * @since_tizen 5.5 + * + * @param[in] handle The component context handle + * @param[out] status The status of the component + * @return @c 0 on success, + * otherwise a negative error value + * + * @remarks This function is only for App Framework internally. + */ +int aul_comp_context_get_status(aul_comp_context_h handle, int *status); + +/** + * @brief Checks whether the component is sub component of the app group or not. + * @since_tizen 5.5 + * + * @param[in] handle The component context handle + * @param[out] is_sub_comp @c true if the component is sub component, \n + * otherwise @c false + * @return @c 0 on success, + * otherwise a negative error value + * + * @remarks This function is only for App Framework internally. + */ +int aul_comp_context_is_sub_comp(aul_comp_context_h handle, bool *is_sub_comp); + +#ifdef __cplusplus +} +#endif diff --git a/include/aul_key.h b/include/aul_key.h index 5988461..9530749 100644 --- a/include/aul_key.h +++ b/include/aul_key.h @@ -654,3 +654,15 @@ * @since_tizen 5.5 */ #define AUL_K_FG_FLAG "__AUL_FG_FLAG__" + +/** + * @brief Definition for AUL: The type of the component. + * @since_tizen 5.5 + */ +#define AUL_K_COMPONENT_TYPE "__AUL_COMPONENT_TYPE__" + +/** + * @breif Definition for AUL: The flag if it's 'true', the component is sub component of the group. + * @since_tizen 5.5 + */ +#define AUL_K_IS_SUB_COMP "__AUL_IS_SUB_COMP__" diff --git a/packaging/aul.spec b/packaging/aul.spec index 2f1bc58..5192f1b 100755 --- a/packaging/aul.spec +++ b/packaging/aul.spec @@ -118,6 +118,7 @@ chsmack -a 'User::Home' %{TZ_SYS_DB}/.component.db-journal %{_bindir}/launch_app %{_bindir}/appid2pid %{_bindir}/launch_debug +%{_bindir}/compmgr_tool %{_datadir}/aul/miregex/* %{_datadir}/aul/preexec_list.txt %{_datadir}/appsvc/* diff --git a/src/aul_cmd.c b/src/aul_cmd.c index bb54372..7e39fa7 100755 --- a/src/aul_cmd.c +++ b/src/aul_cmd.c @@ -264,6 +264,8 @@ API const char *aul_cmd_convert_to_string(int cmd) return "APP_GROUP_GET_GROUP_INFO"; case APP_GROUP_GET_IDLE_INFO: return "APP_GROUP_GET_IDLE_INFO"; + case COMP_CONTEXT_FOREACH: + return "COMP_CONTEXT_FOREACH"; default: return "CUSTOM_COMMAND"; } diff --git a/src/aul_comp_context.c b/src/aul_comp_context.c new file mode 100644 index 0000000..6128929 --- /dev/null +++ b/src/aul_comp_context.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include +#include +#include + +#include +#include + +#include "aul_comp_context.h" +#include "aul_error.h" +#include "aul_util.h" +#include "aul_sock.h" +#include "aul_api.h" +#include "aul.h" + +struct aul_comp_context_s { + const char *comp_id; + const char *instance_id; + const char *app_id; + const char *type; + pid_t pid; + int status; + bool is_sub_comp; +}; + +struct cb_data_s { + aul_comp_context_cb callback; + void *user_data; +}; + +static void __running_context_cb(app_pkt_t *pkt, void *user_data) +{ + struct cb_data_s *cb_data = (struct cb_data_s *)user_data; + struct aul_comp_context_s context; + bundle *b = NULL; + const char *val; + + if (!pkt || !cb_data) { + _E("Invalid parameter"); + return; + } + + if (pkt->cmd == APP_GET_INFO_ERROR) { + _E("Failed to get running component context"); + return; + } + + if (pkt->opt & AUL_SOCK_BUNDLE) + b = bundle_decode(pkt->data, pkt->len); + + if (!b) + return; + + val = bundle_get_val(b, AUL_K_PID); + if (!val) { + bundle_free(b); + return; + } + context.pid = atoi(val); + + val = bundle_get_val(b, AUL_K_STATUS); + if (!val) { + bundle_free(b); + return; + } + context.status = atoi(val); + + val = bundle_get_val(b, AUL_K_IS_SUB_COMP); + if (!val) { + bundle_free(b); + return; + } + context.is_sub_comp = atoi(val); + + context.comp_id = bundle_get_val(b, AUL_K_COMPONENT_ID); + context.instance_id = bundle_get_val(b, AUL_K_INSTANCE_ID); + context.app_id = bundle_get_val(b, AUL_K_APPID); + context.type = bundle_get_val(b, AUL_K_COMPONENT_TYPE); + + cb_data->callback(&context, cb_data->user_data); + bundle_free(b); +} + +API int aul_comp_context_foreach(aul_comp_context_cb callback, + void *user_data) +{ + struct cb_data_s cb_data = { + callback, + user_data + }; + char buf[32]; + bundle *b; + int ret; + int fd; + + if (!callback) { + _E("Invalid parameter"); + return AUL_R_EINVAL; + } + + b = bundle_create(); + if (!b) { + _E("Out of memory"); + return AUL_R_ERROR; + } + + snprintf(buf, sizeof(buf), "%d", getuid()); + bundle_add(b, AUL_K_TARGET_UID, buf); + + fd = aul_sock_send_bundle(AUL_UTIL_PID, getuid(), COMP_CONTEXT_FOREACH, + b, AUL_SOCK_ASYNC); + bundle_free(b); + if (fd < 0) + return aul_error_convert(fd); + + ret = aul_sock_recv_pkt_with_cb(fd, __running_context_cb, &cb_data); + if (ret < 0) + return aul_error_convert(ret); + + return AUL_R_OK; +} + +API int aul_comp_context_get_comp_id(aul_comp_context_h context, + const char **comp_id) +{ + if (!context || !comp_id) { + _E("Invalid parameter"); + return AUL_R_EINVAL; + } + + *comp_id = context->comp_id; + + return AUL_R_OK; +} + +API int aul_comp_context_get_instance_id(aul_comp_context_h context, + const char **instance_id) +{ + if (!context || !instance_id) { + _E("Invalid parameter"); + return AUL_R_EINVAL; + } + + *instance_id = context->instance_id; + + return AUL_R_OK; +} + +API int aul_comp_context_get_app_id(aul_comp_context_h context, + const char **app_id) +{ + if (!context || !app_id) { + _E("Invalid parameter"); + return AUL_R_EINVAL; + } + + *app_id = context->app_id; + + return AUL_R_OK; +} + +API int aul_comp_context_get_type(aul_comp_context_h context, + const char **type) +{ + if (!context || !type) { + _E("Invalid parameter"); + return AUL_R_EINVAL; + } + + *type = context->type; + + return AUL_R_OK; +} + +API int aul_comp_context_get_pid(aul_comp_context_h context, + pid_t *pid) +{ + if (!context || !pid) { + _E("Invalid parameter"); + return AUL_R_EINVAL; + } + + *pid = context->pid; + + return AUL_R_OK; +} + +API int aul_comp_context_get_status(aul_comp_context_h context, + int *status) +{ + if (!context || !status) { + _E("Invalid parameter"); + return AUL_R_EINVAL; + } + + *status = context->status; + + return AUL_R_OK; +} + +API int aul_comp_context_is_sub_comp(aul_comp_context_h context, + bool *is_sub_comp) +{ + if (!context || !is_sub_comp) { + _E("Invalid parameter"); + return AUL_R_EINVAL; + } + + *is_sub_comp = context->is_sub_comp; + + return AUL_R_OK; +} diff --git a/src/aul_comp_info.c b/src/aul_comp_info.c index 4c052e0..9e90f08 100644 --- a/src/aul_comp_info.c +++ b/src/aul_comp_info.c @@ -47,8 +47,8 @@ enum aul_comp_info_e { AUL_COMP_INFO_MAIN_COMP, AUL_COMP_INFO_ICON_DISPLAY, AUL_COMP_INFO_TASKMANAGE, - AUL_COMP_INFO_ICON, AUL_COMP_INFO_LABEL, + AUL_COMP_INFO_ICON, AUL_COMP_INFO_MAX, }; diff --git a/src/aul_comp_status.c b/src/aul_comp_status.c index f0dbaf2..8e72aa4 100644 --- a/src/aul_comp_status.c +++ b/src/aul_comp_status.c @@ -17,10 +17,12 @@ #define _GNU_SOURCE #include #include +#include #include #include +#include "aul_comp_status.h" #include "aul_util.h" #include "aul_sock.h" #include "aul_api.h" diff --git a/tool/CMakeLists.txt b/tool/CMakeLists.txt index e2ddefb..fd4c5d7 100644 --- a/tool/CMakeLists.txt +++ b/tool/CMakeLists.txt @@ -40,3 +40,8 @@ add_executable(app_com_tool app_com_tool.c) target_link_libraries(app_com_tool aul ${pkgs_LDFLAGS} "-pie") INSTALL(TARGETS app_com_tool DESTINATION bin) + +add_executable(compmgr_tool + compmgr_tool.c) +target_link_libraries(compmgr_tool aul ${pkgs_LDFLAGS} "-pie") +INSTALL(TARGETS compmgr_tool DESTINATION bin) diff --git a/tool/compmgr_tool.c b/tool/compmgr_tool.c new file mode 100644 index 0000000..7c2c183 --- /dev/null +++ b/tool/compmgr_tool.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aul.h" +#include "aul_comp_info.h" +#include "aul_comp_context.h" + +enum command_e { + CMD_LIST, + CMD_RUNNING_LIST, + CMD_MAX, +}; + +enum option_e { + OPT_USER, + OPT_MAX, +}; + +struct command { + const char *name; + int (*init)(void *data); + int (*run)(void *data); + void (*finish)(void *data); +}; + +static GMainLoop *loop; +static gchar *help; +static gpointer cmd_opt[CMD_MAX]; +static GOptionEntry cmd_entries[] = { + { + .long_name = "list", + .short_name = 'l', + .flags = 0, + .arg = G_OPTION_ARG_NONE, + .arg_data = &cmd_opt[CMD_LIST], + .description = "Show installed component list", + .arg_description = NULL + }, + { + .long_name = "running-list", + .short_name = 'r', + .flags = 0, + .arg = G_OPTION_ARG_NONE, + .arg_data = &cmd_opt[CMD_RUNNING_LIST], + .description = "Show the running components information", + .arg_description = NULL + }, + { + NULL + } +}; +static gpointer opt[OPT_MAX]; +static GOptionEntry opt_entries[] = { + { + .long_name = "user", + .short_name = 'u', + .flags = 0, + .arg = G_OPTION_ARG_INT, + .arg_data = &opt[OPT_USER], + .description = "Specify the user ID", + .arg_description = "USER ID" + }, + { + NULL + } +}; + +static GOptionGroup *__get_opt_group(void) +{ + GOptionGroup *group; + + group = g_option_group_new("option", "Additional Options:", + "Additional options", NULL, NULL); + if (!group) + return NULL; + + g_option_group_add_entries(group, opt_entries); + + return group; +} + +static void __cmd_common_finish(void *data) +{ + g_main_loop_quit(loop); +} + +static bool __comp_info_cb(aul_comp_info_h handle, void *user_data) +{ + int *member_count = (int *)user_data; + const char *comp_id = NULL; + const char *type = NULL; + const char *launch_mode = NULL; + bool main_comp = false; + bool icon_display = false; + bool taskmanage = false; + const char *icon = NULL; + const char *label = NULL; + const char *boolean_string[] = { + "false", + "true", + }; + + aul_comp_info_get_comp_id(handle, &comp_id); + aul_comp_info_get_type(handle, &type); + aul_comp_info_get_launch_mode(handle, &launch_mode); + aul_comp_info_is_main_comp(handle, &main_comp); + aul_comp_info_is_icon_display(handle, &icon_display); + aul_comp_info_is_taskmanage(handle, &taskmanage); + aul_comp_info_get_icon(handle, &icon); + aul_comp_info_get_label(handle, &label); + + (*member_count)++; + printf("----------------------------------\n"); + printf("--- Member : %d\n", *member_count); + printf(" - ID : %s\n", comp_id); + printf(" - Type : %s\n", type); + printf(" - Launch Mode : %s\n", launch_mode); + printf(" - Main Comp : %s\n", boolean_string[main_comp]); + printf(" - TaskManage : %s\n", boolean_string[taskmanage]); + printf(" - Icon Display : %s\n", boolean_string[icon_display]); + printf(" - Icon : %s\n", icon ? icon : ""); + printf(" - Label : %s\n", label ? label : ""); + printf("\n"); + + return true; +} + +static int __installed_list_cb(const pkgmgrinfo_appinfo_h handle, void *data) +{ + uid_t uid = GPOINTER_TO_UINT(data); + char *comp_type = NULL; + char *appid = NULL; + int member_count = 0; + int ret; + + pkgmgrinfo_appinfo_get_component_type(handle, &comp_type); + if (comp_type && strcmp(comp_type, "componentbasedapp") != 0) + return 0; + + pkgmgrinfo_appinfo_get_appid(handle, &appid); + if (!appid) + return -1; + + printf("----------------------------------\n"); + printf("< Application : %s >\n", appid); + ret = aul_comp_info_foreach_usr(appid, uid, __comp_info_cb, + (void *)&member_count); + if (ret < 0) { + fprintf(stderr, "Failed to retrieve component info. %s:%u\n", + appid, uid); + return -1; + } + printf("Member count : %d\n", member_count); + printf("\n"); + + return 0; +} + +static int __cmd_list_run(void *data) +{ + uid_t uid; + int ret; + + if (opt[OPT_USER]) + uid = GPOINTER_TO_UINT(opt[OPT_USER]); + else + uid = getuid(); + + ret = pkgmgrinfo_appinfo_get_usr_installed_list(__installed_list_cb, + uid, GUINT_TO_POINTER(uid)); + if (ret == PMINFO_R_OK) { + printf("==================================\n"); + printf("\n"); + } + + return ret; +} + +static const char *__get_status_string(int status) +{ + switch (status) { + case STATUS_LAUNCHING: + return "STATUS_LAUNCHING"; + case STATUS_CREATED: + return "STATUS_CREATED"; + case STATUS_FOCUS: + return "STATUS_FOCUS"; + case STATUS_VISIBLE: + return "STATUS_VISIBLE"; + case STATUS_BG: + return "STATUS_BG"; + case STATUS_DYING: + return "STATUS_DYING"; + default: + return "Unknown Status"; + } +} + +static void __comp_context_cb(aul_comp_context_h handle, void *user_data) +{ + int *member_count = (int *)user_data; + const char *app_id = NULL; + const char *instance_id = NULL; + const char *comp_id = NULL; + const char *type = NULL; + pid_t pid = -1; + int status = -1; + bool is_sub_comp = false; + + aul_comp_context_get_app_id(handle, &app_id); + aul_comp_context_get_instance_id(handle, &instance_id); + aul_comp_context_get_comp_id(handle, &comp_id); + aul_comp_context_get_type(handle, &type); + aul_comp_context_get_pid(handle, &pid); + aul_comp_context_get_status(handle, &status); + aul_comp_context_is_sub_comp(handle, &is_sub_comp); + + (*member_count)++; + printf("----------------------------------\n"); + printf("< Member : %d >\n", *member_count); + printf("--- ID : %s\n", comp_id); + printf(" - Instance ID : %s\n", instance_id); + printf(" - Application ID : %s\n", app_id); + printf(" - Type : %s\n", type); + printf(" - Process ID : %d\n", pid); + printf(" - Status : %s\n", __get_status_string(status)); + printf(" - Sub Component : %s\n", is_sub_comp ? "true" : "false"); +} + +static int __cmd_running_list_run(void *data) +{ + int member_count = 0; + int ret; + + ret = aul_comp_context_foreach(__comp_context_cb, + (void *)&member_count); + if (ret == AUL_R_OK) { + printf("==================================\n"); + printf("\n"); + printf("Component count : %d\n", member_count); + } + + return ret; +} + +static struct command cmd_table[] = { + [CMD_LIST] = { + .name = "list", + .init = NULL, + .run = __cmd_list_run, + .finish = __cmd_common_finish + }, + [CMD_RUNNING_LIST] = { + .name = "running-list", + .init = NULL, + .run = __cmd_running_list_run, + .finish = __cmd_common_finish + }, +}; + +static struct command *__find_cmd(void) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS(cmd_table); ++i) { + if (cmd_opt[i]) + return &cmd_table[i]; + } + + return NULL; +} + +static gboolean __run_cmd(gpointer data) +{ + struct command *cmd; + int result; + + cmd = __find_cmd(); + if (cmd == NULL) { + printf("%s", help); + g_main_loop_quit(loop); + return G_SOURCE_REMOVE; + } + + if (cmd->init) { + result = cmd->init(data); + if (result != 0) { + g_main_loop_quit(loop); + return G_SOURCE_REMOVE; + } + } + + if (cmd->run) { + result = cmd->run(data); + if (result != 0) { + g_main_loop_quit(loop); + return G_SOURCE_REMOVE; + } + } + + if (cmd->finish) + cmd->finish(data); + + return G_SOURCE_REMOVE; +} + +int main(int argc, char *argv[]) +{ + GOptionContext *context; + GOptionGroup *opt_group; + GError *error = NULL; + + context = g_option_context_new(NULL); + g_option_context_add_main_entries(context, cmd_entries, NULL); + + opt_group = __get_opt_group(); + if (!opt_group) { + printf("Failed to get opt group\n"); + g_option_context_free(context); + return -1; + } + g_option_context_add_group(context, opt_group); + + if (!g_option_context_parse(context, &argc, &argv, &error)) { + printf("%s: %s\n", argv[0], error->message); + g_option_context_free(context); + g_clear_error(&error); + return -1; + } + + help = g_option_context_get_help(context, TRUE, NULL); + g_option_context_free(context); + + g_idle_add(__run_cmd, NULL); + loop = g_main_loop_new(NULL, FALSE); + if (!loop) { + printf("Failed to create glib main loop\n"); + exit(EXIT_FAILURE); + } + g_main_loop_run(loop); + g_main_loop_unref(loop); + free(help); + + return 0; +}