From 104651c33732f688b11829024aac45d82085b046 Mon Sep 17 00:00:00 2001 From: Jiyong Min Date: Wed, 17 May 2017 15:29:57 +0900 Subject: Fix the problem getting wrong server & playback state for latest_server after reboot and change the location of header files Change-Id: I2e1095e7548ec70002b4733fdae939f7fc3dd086 Signed-off-by: jiyong min --- CMakeLists.txt | 2 +- packaging/capi-media-controller.spec | 2 +- svc/daemon/media_controller_main.c | 4 +- svc/include/media_controller_cynara.h | 40 ++++++++++++++++++ svc/include/media_controller_db_util.h | 43 +++++++++++++++++++ svc/include/media_controller_socket.h | 77 ++++++++++++++++++++++++++++++++++ svc/include/media_controller_svc.h | 45 ++++++++++++++++++++ svc/media_controller_cynara.h | 40 ------------------ svc/media_controller_db_util.c | 57 +++++++++++++++++++++++++ svc/media_controller_db_util.h | 40 ------------------ svc/media_controller_socket.h | 77 ---------------------------------- svc/media_controller_svc.c | 5 +++ svc/media_controller_svc.h | 45 -------------------- 13 files changed, 271 insertions(+), 206 deletions(-) create mode 100644 svc/include/media_controller_cynara.h create mode 100755 svc/include/media_controller_db_util.h create mode 100644 svc/include/media_controller_socket.h create mode 100755 svc/include/media_controller_svc.h delete mode 100644 svc/media_controller_cynara.h mode change 100644 => 100755 svc/media_controller_db_util.c delete mode 100755 svc/media_controller_db_util.h delete mode 100644 svc/media_controller_socket.h delete mode 100755 svc/media_controller_svc.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d52595..78c61d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(VERSION ${version}) SET(INC_DIR include) -SET(SVC_DIR svc) +SET(SVC_DIR svc/include) INCLUDE_DIRECTORIES(${INC_DIR} ${SVC_DIR}) diff --git a/packaging/capi-media-controller.spec b/packaging/capi-media-controller.spec index f3ced4b..d0a2966 100755 --- a/packaging/capi-media-controller.spec +++ b/packaging/capi-media-controller.spec @@ -1,6 +1,6 @@ Name: capi-media-controller Summary: A media controller library in Tizen Native API -Version: 0.1.33 +Version: 0.1.34 Release: 1 Group: Multimedia/API License: Apache-2.0 diff --git a/svc/daemon/media_controller_main.c b/svc/daemon/media_controller_main.c index f71cf8c..4bca35a 100644 --- a/svc/daemon/media_controller_main.c +++ b/svc/daemon/media_controller_main.c @@ -15,8 +15,8 @@ */ #include "media_controller_private.h" -#include "../media_controller_socket.h" -#include "../media_controller_svc.h" +#include "media_controller_socket.h" +#include "media_controller_svc.h" #include "media_controller_cynara.h" GMainLoop *g_mc_mainloop = NULL; diff --git a/svc/include/media_controller_cynara.h b/svc/include/media_controller_cynara.h new file mode 100644 index 0000000..743ae82 --- /dev/null +++ b/svc/include/media_controller_cynara.h @@ -0,0 +1,40 @@ +/* +* Copyright (c) 2011 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. +*/ + +#ifndef __TIZEN_MEDIA_CONTROLLER_CYNARA_H__ +#define __TIZEN_MEDIA_CONTROLLER_CYNARA_H__ + +#include + +#include + +#define MC_CLIENT_PRIVILEGE "http://tizen.org/privilege/mediacontroller.client" +#define MC_SERVER_PRIVILEGE "http://tizen.org/privilege/mediacontroller.server" + +typedef struct { + pid_t pid; + char *uid; + char *smack; +} mc_peer_creds; + +int mc_cynara_initialize(void); +int mc_cynara_check(const mc_peer_creds *creds, const char *privilege); +int mc_cynara_receive_untrusted_message(int sockfd, mc_comm_msg_s *recv_msg, mc_peer_creds *credentials); +int mc_cynara_enable_credentials_passing(int sockfd); +void mc_cynara_finish(void); + + +#endif/* _MEDIA_CONTROLLER_CYNARA_H_ */ diff --git a/svc/include/media_controller_db_util.h b/svc/include/media_controller_db_util.h new file mode 100755 index 0000000..1ec5ec5 --- /dev/null +++ b/svc/include/media_controller_db_util.h @@ -0,0 +1,43 @@ +/* +* Copyright (c) 2011 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. +*/ + +#ifndef __TIZEN_MEDIA_CONTROLLER_DB_UTIL_H__ +#define __TIZEN_MEDIA_CONTROLLER_DB_UTIL_H__ + +#include +#include +#include + +#define MC_DB_NAME ".media_controller.db" + +#define MC_DB_TABLE_SERVER_LIST "server_list" +#define MC_DB_TABLE_LATEST_SERVER "latest_server" + +#define DB_SELECT_ALL_SERVER_LIST_EXCEPT_LATEST "SELECT name FROM SQLITE_MASTER WHERE type='table' AND (name != '%q') AND (name NOT IN (SELECT server_name FROM "MC_DB_TABLE_LATEST_SERVER"));" +#define DB_SELECT_LATEST_SERVER "SELECT server_name FROM "MC_DB_TABLE_LATEST_SERVER";" +#define DB_UPDATE_STATES "UPDATE '%q' SET server_state=%d, playback_state=%d;" + +#define SQLITE3_SAFE_FREE(sql_string) {if (sql_string) {sqlite3_free(sql_string); sql_string = NULL; } } +#define SQLITE3_FINALIZE(x) {if (x != NULL) sqlite3_finalize(x); } + +int mc_db_util_connect(void **handle, uid_t uid); +int mc_db_util_disconnect(void *handle); +int mc_db_util_create_tables(void *handle); +int mc_db_util_update_db(void *handle, const char *sql_str); +int mc_db_util_delete_whole_server_tables(void *handle); +int mc_db_util_init_latest_server_table(void *handle); + +#endif /*__TIZEN_MEDIA_CONTROLLER_DB_UTIL_H__*/ diff --git a/svc/include/media_controller_socket.h b/svc/include/media_controller_socket.h new file mode 100644 index 0000000..2a5bba1 --- /dev/null +++ b/svc/include/media_controller_socket.h @@ -0,0 +1,77 @@ +/* +* Copyright (c) 2011 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. +*/ + +#ifndef __TIZEN_MEDIA_CONTROLLER_SOCKET_H__ +#define __TIZEN_MEDIA_CONTROLLER_SOCKET_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define SERVER_IP "127.0.0.1" +#define MC_TIMEOUT_SEC_5 5 /**< Response from Server time out */ +#define MAX_MSG_SIZE 4096*2 +#define MC_SOCK_NOT_ALLOCATE -1 +#define MC_SOCK_ACTIVATION_PATH "/run/.mediacontroller.sock" /* tzplatform_mkpath(TZ_SYS_RUN, ".media_controller.sock") */ +#define MC_IPC_PATH "/run/.mediacontroller-comm.sock" /* tzplatform_mkpath(TZ_SYS_RUN, ".media_controller-comm.sock") */ +#define MC_SERVER_CONNECTION_MSG "Connect" +#define MC_SERVER_DISCONNECTION_MSG "Disonnect" + +typedef enum { + MC_DB_UPDATE_PORT, /**< Media Controller DB Update */ + MC_PORT_MAX, +} mc_msg_port_type_e; + +typedef enum { + MC_MSG_DB_UPDATE, /**< Media Controller DB Update */ + MC_MSG_CLIENT_SET, + MC_MSG_CLIENT_GET, + MC_MSG_SERVER_CONNECTION, + MC_MSG_SERVER_DISCONNECTION, + MC_MSG_MAX, +} mc_msg_type_e; + +typedef struct { + int sock_fd; + char *sock_path; +} mc_sock_info_s; + +typedef struct { + mc_msg_type_e msg_type; + int pid; + uid_t uid; + int result; + size_t msg_size; /*this is size of message below and this does not include the terminationg null byte ('\0'). */ + char msg[MAX_MSG_SIZE]; +} mc_comm_msg_s; + +int mc_ipc_create_client_socket(int timeout_sec, mc_sock_info_s* sock_info); +int mc_ipc_delete_client_socket(mc_sock_info_s* sock_info); +int mc_ipc_create_server_socket(mc_msg_port_type_e port, int *sock_fd); +int mc_ipc_send_msg_to_client_tcp(int sockfd, mc_comm_msg_s *send_msg, struct sockaddr_un *client_addr); +int mc_ipc_receive_message_tcp(int client_sock, mc_comm_msg_s *recv_msg); +int mc_ipc_accept_client_tcp(int serv_sock, int* client_sock); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIA_CONTROLLER_SERVER_H__ */ diff --git a/svc/include/media_controller_svc.h b/svc/include/media_controller_svc.h new file mode 100755 index 0000000..709c206 --- /dev/null +++ b/svc/include/media_controller_svc.h @@ -0,0 +1,45 @@ +/* +* Copyright (c) 2011 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. +*/ + +#ifndef _MEDIA_CONTROLLER_SVC_H_ +#define _MEDIA_CONTROLLER_SVC_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct { + int pid; + char *data; +} mc_svc_list_t; + +typedef struct { + void *db_handle; + void *mc_svc_list; +} mc_svc_data_t; + +int mc_create_socket_activation(void); +gboolean mc_svc_thread(void *data); +GMainLoop *mc_svc_get_main_loop(void); +int mc_svc_get_connection_cnt(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif/* _MEDIA_CONTROLLER_SVC_H_ */ diff --git a/svc/media_controller_cynara.h b/svc/media_controller_cynara.h deleted file mode 100644 index 743ae82..0000000 --- a/svc/media_controller_cynara.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -* Copyright (c) 2011 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. -*/ - -#ifndef __TIZEN_MEDIA_CONTROLLER_CYNARA_H__ -#define __TIZEN_MEDIA_CONTROLLER_CYNARA_H__ - -#include - -#include - -#define MC_CLIENT_PRIVILEGE "http://tizen.org/privilege/mediacontroller.client" -#define MC_SERVER_PRIVILEGE "http://tizen.org/privilege/mediacontroller.server" - -typedef struct { - pid_t pid; - char *uid; - char *smack; -} mc_peer_creds; - -int mc_cynara_initialize(void); -int mc_cynara_check(const mc_peer_creds *creds, const char *privilege); -int mc_cynara_receive_untrusted_message(int sockfd, mc_comm_msg_s *recv_msg, mc_peer_creds *credentials); -int mc_cynara_enable_credentials_passing(int sockfd); -void mc_cynara_finish(void); - - -#endif/* _MEDIA_CONTROLLER_CYNARA_H_ */ diff --git a/svc/media_controller_db_util.c b/svc/media_controller_db_util.c old mode 100644 new mode 100755 index 763e021..16bcf51 --- a/svc/media_controller_db_util.c +++ b/svc/media_controller_db_util.c @@ -312,3 +312,60 @@ int mc_db_util_delete_whole_server_tables(void *handle) return ret; } + +int mc_db_util_init_latest_server_table(void *handle) +{ + int ret = MEDIA_CONTROLLER_ERROR_NONE; + sqlite3 *db_handle = (sqlite3 *)handle; + char *sql_str = NULL; + sqlite3_stmt *stmt = NULL; + char *latest_server_name = NULL; + + mc_retvm_if(handle == NULL, MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + /* Get latest server name */ + sql_str = sqlite3_mprintf(DB_SELECT_LATEST_SERVER); + mc_retvm_if(!MC_STRING_VALID(sql_str), MEDIA_CONTROLLER_ERROR_INVALID_OPERATION, "SQL string is null"); + + ret = sqlite3_prepare_v2(db_handle, sql_str, strlen(sql_str), &stmt, NULL); + if (SQLITE_OK != ret) { + mc_error("prepare error [%s]\n", sqlite3_errmsg(db_handle)); + SQLITE3_SAFE_FREE(sql_str); + return MEDIA_CONTROLLER_ERROR_INVALID_OPERATION; + } + + ret = sqlite3_step(stmt); + while (SQLITE_ROW == ret) { + if (sqlite3_column_int(stmt, 0) == 0) { + mc_debug("latest_server table does not exist"); + SQLITE3_FINALIZE(stmt); + SQLITE3_SAFE_FREE(sql_str); + return MEDIA_CONTROLLER_ERROR_NONE; + } + if (MC_STRING_VALID((const char *)sqlite3_column_text(stmt, 1))) { + latest_server_name = strdup((const char *)sqlite3_column_text(stmt, 1)); + mc_debug("latest_server_name: %s", latest_server_name); + } + ret = sqlite3_step(stmt); + } + + SQLITE3_FINALIZE(stmt); + SQLITE3_SAFE_FREE(sql_str); + + mc_retvm_if(latest_server_name == NULL, MEDIA_CONTROLLER_ERROR_OUT_OF_MEMORY, "latest_server is not exist"); + + /* Update server_state and playbakc_state to 0 */ + sql_str = sqlite3_mprintf(DB_UPDATE_STATES, latest_server_name, MC_SERVER_STATE_NONE, MC_PLAYBACK_STATE_NONE); + mc_retvm_if(!MC_STRING_VALID(sql_str), MEDIA_CONTROLLER_ERROR_INVALID_OPERATION, "SQL string is null"); + + ret = mc_db_util_update_db(handle, sql_str); + if (ret != MEDIA_CONTROLLER_ERROR_NONE) { + mc_error("Error mc_db_util_update_db %d", ret); + SQLITE3_SAFE_FREE(sql_str); + return ret; + } + + SQLITE3_SAFE_FREE(sql_str); + + return ret; +} diff --git a/svc/media_controller_db_util.h b/svc/media_controller_db_util.h deleted file mode 100755 index 78386ff..0000000 --- a/svc/media_controller_db_util.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -* Copyright (c) 2011 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. -*/ - -#ifndef __TIZEN_MEDIA_CONTROLLER_DB_UTIL_H__ -#define __TIZEN_MEDIA_CONTROLLER_DB_UTIL_H__ - -#include -#include -#include - -#define MC_DB_NAME ".media_controller.db" - -#define MC_DB_TABLE_SERVER_LIST "server_list" -#define MC_DB_TABLE_LATEST_SERVER "latest_server" - -#define DB_SELECT_ALL_SERVER_LIST_EXCEPT_LATEST "SELECT name FROM SQLITE_MASTER WHERE type='table' AND (name != '%q') AND (name NOT IN (SELECT server_name FROM "MC_DB_TABLE_LATEST_SERVER"))" - -#define SQLITE3_SAFE_FREE(sql_string) {if (sql_string) {sqlite3_free(sql_string); sql_string = NULL; } } -#define SQLITE3_FINALIZE(x) {if (x != NULL) sqlite3_finalize(x); } - -int mc_db_util_connect(void **handle, uid_t uid); -int mc_db_util_disconnect(void *handle); -int mc_db_util_create_tables(void *handle); -int mc_db_util_update_db(void *handle, const char *sql_str); -int mc_db_util_delete_whole_server_tables(void *handle); - -#endif /*__TIZEN_MEDIA_CONTROLLER_DB_UTIL_H__*/ diff --git a/svc/media_controller_socket.h b/svc/media_controller_socket.h deleted file mode 100644 index 2a5bba1..0000000 --- a/svc/media_controller_socket.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -* Copyright (c) 2011 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. -*/ - -#ifndef __TIZEN_MEDIA_CONTROLLER_SOCKET_H__ -#define __TIZEN_MEDIA_CONTROLLER_SOCKET_H__ - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define SERVER_IP "127.0.0.1" -#define MC_TIMEOUT_SEC_5 5 /**< Response from Server time out */ -#define MAX_MSG_SIZE 4096*2 -#define MC_SOCK_NOT_ALLOCATE -1 -#define MC_SOCK_ACTIVATION_PATH "/run/.mediacontroller.sock" /* tzplatform_mkpath(TZ_SYS_RUN, ".media_controller.sock") */ -#define MC_IPC_PATH "/run/.mediacontroller-comm.sock" /* tzplatform_mkpath(TZ_SYS_RUN, ".media_controller-comm.sock") */ -#define MC_SERVER_CONNECTION_MSG "Connect" -#define MC_SERVER_DISCONNECTION_MSG "Disonnect" - -typedef enum { - MC_DB_UPDATE_PORT, /**< Media Controller DB Update */ - MC_PORT_MAX, -} mc_msg_port_type_e; - -typedef enum { - MC_MSG_DB_UPDATE, /**< Media Controller DB Update */ - MC_MSG_CLIENT_SET, - MC_MSG_CLIENT_GET, - MC_MSG_SERVER_CONNECTION, - MC_MSG_SERVER_DISCONNECTION, - MC_MSG_MAX, -} mc_msg_type_e; - -typedef struct { - int sock_fd; - char *sock_path; -} mc_sock_info_s; - -typedef struct { - mc_msg_type_e msg_type; - int pid; - uid_t uid; - int result; - size_t msg_size; /*this is size of message below and this does not include the terminationg null byte ('\0'). */ - char msg[MAX_MSG_SIZE]; -} mc_comm_msg_s; - -int mc_ipc_create_client_socket(int timeout_sec, mc_sock_info_s* sock_info); -int mc_ipc_delete_client_socket(mc_sock_info_s* sock_info); -int mc_ipc_create_server_socket(mc_msg_port_type_e port, int *sock_fd); -int mc_ipc_send_msg_to_client_tcp(int sockfd, mc_comm_msg_s *send_msg, struct sockaddr_un *client_addr); -int mc_ipc_receive_message_tcp(int client_sock, mc_comm_msg_s *recv_msg); -int mc_ipc_accept_client_tcp(int serv_sock, int* client_sock); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __TIZEN_MEDIA_CONTROLLER_SERVER_H__ */ diff --git a/svc/media_controller_svc.c b/svc/media_controller_svc.c index 52f4393..8df46e0 100755 --- a/svc/media_controller_svc.c +++ b/svc/media_controller_svc.c @@ -284,6 +284,11 @@ gboolean mc_svc_thread(void *data) return FALSE; } + /* Initialize latest server table */ + if (mc_db_util_init_latest_server_table(mc_svc_data->db_handle) != MEDIA_CONTROLLER_ERROR_NONE) { + mc_error("mc_db_util_init_latest_server_table failed"); + } + /* Create TCP Socket*/ ret = mc_ipc_create_server_socket(MC_DB_UPDATE_PORT, &sockfd); if (ret != MEDIA_CONTROLLER_ERROR_NONE) { diff --git a/svc/media_controller_svc.h b/svc/media_controller_svc.h deleted file mode 100755 index 709c206..0000000 --- a/svc/media_controller_svc.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -* Copyright (c) 2011 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. -*/ - -#ifndef _MEDIA_CONTROLLER_SVC_H_ -#define _MEDIA_CONTROLLER_SVC_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef struct { - int pid; - char *data; -} mc_svc_list_t; - -typedef struct { - void *db_handle; - void *mc_svc_list; -} mc_svc_data_t; - -int mc_create_socket_activation(void); -gboolean mc_svc_thread(void *data); -GMainLoop *mc_svc_get_main_loop(void); -int mc_svc_get_connection_cnt(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif/* _MEDIA_CONTROLLER_SVC_H_ */ -- cgit v1.2.3