Add multi-user activation 27/43427/3 accepted/tizen/mobile/20150709.111132 accepted/tizen/tv/20150709.111423 accepted/tizen/wearable/20150709.111251 submit/tizen/20150709.092456
authorJi Yong Min <jiyong.min@samsung.com>
Thu, 9 Jul 2015 04:42:08 +0000 (13:42 +0900)
committerJi Yong Min <jiyong.min@samsung.com>
Thu, 9 Jul 2015 06:07:44 +0000 (15:07 +0900)
- modify to setup db in user-session
- modify to use db to read & write by uid(use db in user-session)
- modify service to root daemon temporary
- remove smack labels

Change-Id: I5aec404dc9d5c3a7c8d01767c15b82623a867100
Signed-off-by: Jiyong Min <jiyong.min@samsung.com>
14 files changed:
include/media_controller_db.h
packaging/capi-media-controller.spec
packaging/media-controller-user.service [new file with mode: 0755]
packaging/media-controller_create_db.sh
packaging/mediacontroller.service
packaging/mediacontroller.socket
src/media_controller_db.c
src/media_controller_ipc.c
svc/media_controller_db_util.c
svc/media_controller_db_util.h
svc/media_controller_socket.c
svc/media_controller_socket.h
svc/media_controller_svc.c
test/server_test/media_controller_server_test.c

index 9a79341..1bdb956 100755 (executable)
@@ -21,7 +21,7 @@
 #include <sqlite3.h>
 #include <tzplatform_config.h>
 
-#define MC_DB_NAME tzplatform_mkpath(TZ_SYS_DB, ".media_controller.db")
+#define MC_DB_NAME ".media_controller.db"
 
 #define MC_DB_TABLE_SERVER_LIST                "server_list"
 #define MC_DB_TABLE_LATEST_SERVER              "latest_server"
index 4f61058..d50c8a1 100755 (executable)
@@ -1,15 +1,16 @@
 Name:       capi-media-controller
 Summary:    Multimedia Controller for player application
-Version:    0.0.3
+Version:    0.0.4
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0
 Source0:    %{name}-%{version}.tar.gz
 Source1:    mediacontroller.service
 Source2:    mediacontroller.socket
+Source3:    media-controller-user.service
 Source1001: media-controller_create_db.sh
-Requires(post):  /sbin/ldconfig
-Requires(postun):  /sbin/ldconfig
+#Requires(post):  /sbin/ldconfig
+#Requires(postun):  /sbin/ldconfig
 BuildRequires:  cmake
 BuildRequires:  sqlite
 BuildRequires:  pkgconfig(capi-base-common)
@@ -63,29 +64,28 @@ install -m 644 %{SOURCE1} %{buildroot}%{_unitdir}/mediacontroller.service
 install -m 644 %{SOURCE2} %{buildroot}%{_unitdir}/mediacontroller.socket
 ln -s ../mediacontroller.socket %{buildroot}%{_unitdir}/sockets.target.wants/mediacontroller.socket
 
-#Create DB
+# Setup DB creation in user session
+mkdir -p %{buildroot}%{_unitdir_user}/default.target.wants/
+install -m 644 %{SOURCE3} %{buildroot}%{_unitdir_user}/media-controller-user.service
+ln -sf ../media-controller-user.service %{buildroot}%{_unitdir_user}/default.target.wants/media-controller-user.service
+
+# Create DB for multi-user
 mkdir -p %{buildroot}%{_bindir}
 install -m 0775 %{SOURCE1001} %{buildroot}%{_bindir}/media-controller_create_db.sh
-mkdir -p %{buildroot}%{TZ_SYS_DB}
-sqlite3 %{buildroot}%{TZ_SYS_DB}/.media_controller.db 'PRAGMA journal_mode = PERSIST; PRAGMA user_version=1;'
 
 mkdir -p %{buildroot}/usr/share/license
 cp LICENSE.APLv2.0 %{buildroot}/usr/share/license/%{name}
 
-%post -p /sbin/ldconfig
+%post
 chgrp %TZ_SYS_USER_GROUP %{_bindir}/media-controller_create_db.sh
-%postun -p /sbin/ldconfig
+%postun
 
 %files
 %defattr(-,root,root,-)
 %{_libdir}/*.so.*
 %{_bindir}/media-controller_create_db.sh
 #%{_bindir}/*                  //disable tests
-%manifest capi-media-controller.manifest
-%attr(660,system,app) %{TZ_SYS_DB}/.media_controller.db
-%attr(660,system,app) %{TZ_SYS_DB}/.media_controller.db-journal
-%config(noreplace) %{TZ_SYS_DB}/.media_controller.db
-%config(noreplace) %{TZ_SYS_DB}/.media_controller.db-journal
+%manifest %{name}.manifest
 /usr/share/license/%{name}
 
 %files -n mediacontroller
@@ -95,8 +95,8 @@ chgrp %TZ_SYS_USER_GROUP %{_bindir}/media-controller_create_db.sh
 %{_unitdir}/mediacontroller.service
 %{_unitdir}/mediacontroller.socket
 %{_unitdir}/sockets.target.wants/mediacontroller.socket
-#change owner
-#chown 200:5000 %{TZ_SYS_DB}/.media_controller.db*
+%{_unitdir_user}/media-controller-user.service
+%{_unitdir_user}/default.target.wants/media-controller-user.service
 
 %files devel
 %defattr(-,root,root,-)
diff --git a/packaging/media-controller-user.service b/packaging/media-controller-user.service
new file mode 100755 (executable)
index 0000000..a7b5e1a
--- /dev/null
@@ -0,0 +1,12 @@
+[Unit]
+Description=Media controller user
+
+[Service]
+Type=idle
+CPUAccounting=true
+CPUQuota=5%
+ExecStartPre=/usr/bin/sleep 5
+ExecStart=/usr/bin/sh -c "/usr/bin/media-controller_create_db.sh"
+
+[Install]
+WantedBy=default.target
index a112bce..c691ca7 100755 (executable)
@@ -2,16 +2,23 @@
 
 source /etc/tizen-platform.conf
 
-mkdir -p $TZ_SYS_DB
+mkdir -p $TZ_USER_DB
 
 #Create DB file
-sqlite3 ${TZ_SYS_DB}/.media_controller.db 'PRAGMA journal_mode = PERSIST;'
+sqlite3 ${TZ_USER_DB}/.media_controller.db 'PRAGMA journal_mode = PERSIST;
+               CREATE TABLE IF NOT EXISTS latest_server (server_name TEXT PRIMARY KEY);
+'
 
 #Change permission
-chmod 664 ${TZ_SYS_DB}/.media_controller.db
-chmod 664 ${TZ_SYS_DB}/.media_controller.db-journal
+chmod 644 ${TZ_USER_DB}/.media_controller.db
+chmod 644 ${TZ_USER_DB}/.media_controller.db-journal
+
+#if [ -f /opt/usr/dbspace/.media_controller.db ]
+#then
+#        chsmack -a 'mediacontroller::db' /opt/usr/dbspace/.media_controller.db*
+#fi
 
 #Change group (6017: db_filemanager 5000: app)
-chgrp $TZ_SYS_USER_GROUP ${TZ_SYS_DB}
-chgrp 6017 ${TZ_SYS_DB}/.media_controller.db
-chgrp 6017 ${TZ_SYS_DB}/.media_controller.db-journal
+chgrp $TZ_SYS_USER_GROUP ${TZ_USER_DB}
+chgrp 6017 ${TZ_USER_DB}/.media_controller.db
+chgrp 6017 ${TZ_USER_DB}/.media_controller.db-journal
index 035f1a7..f8fd79d 100755 (executable)
@@ -2,11 +2,8 @@
 Description=Media controller
 
 [Service]
-User=system
-Group=system
-SmackProcessLabel=mediacontroller
 ExecStart=/usr/bin/mediacontroller
 Type=simple
 
 [Install]
-WantedBy=multi-user.target
+Also=mediacontroller.socket
index 12e08ee..e1db656 100755 (executable)
@@ -4,9 +4,7 @@ Description=MediaController Service socket
 [Socket]
 SocketUser=system
 SocketGroup=system
-ListenStream=/var/run/mediacontroller/media_sa_controller
-SmackLabelIPIn=mediacontroller
-SmackLabelIPOut=mediacontroller
+ListenStream=/var/run/media-controller/media_sa_controller
 Service=mediacontroller.service
 
 [Install]
index d58ea3a..6b99458 100755 (executable)
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <tzplatform_config.h>
+#include <sys/stat.h>
 
 #include "media_controller_private.h"
 #include "media_controller_db.h"
@@ -38,6 +46,9 @@ typedef enum {
        MC_SERVER_FIELD_REPEAT_MODE,
 } server_table_field_e;
 
+#define FAT_FILEPATH_LEN_MAX           4096    /* inc null */
+#define MC_FILE_PATH_LEN_MAX           FAT_FILEPATH_LEN_MAX             /**< File path max length (include file name) on file system */
+
 static int __mc_db_busy_handler(void *pData, int count)
 {
        usleep(50000);
@@ -166,6 +177,63 @@ static int __mc_db_get_ulong_value_of_key(void *handle, const char *server_name,
        return MEDIA_CONTROLLER_ERROR_NONE;
 }
 
+static char* __mc_get_db_name(uid_t uid)
+{
+       char result_psswd[MC_FILE_PATH_LEN_MAX];
+       char *result_psswd_rtn = NULL;
+       struct group *grpinfo = NULL;
+       char * dir = NULL;
+
+       memset(result_psswd, 0, sizeof(result_psswd));
+       if(uid == getuid())
+       {
+               strncpy(result_psswd, MC_DB_NAME, sizeof(result_psswd));
+               grpinfo = getgrnam("users");
+               if(grpinfo == NULL) {
+                       mc_error("getgrnam(users) returns NULL !");
+                       return NULL;
+               }
+       }
+       else
+       {
+               struct passwd *userinfo = getpwuid(uid);
+               if(userinfo == NULL) {
+                       mc_error("getpwuid(%d) returns NULL !", uid);
+                       return NULL;
+               }
+               grpinfo = getgrnam("users");
+               if(grpinfo == NULL) {
+                       mc_error("getgrnam(users) returns NULL !");
+                       return NULL;
+               }
+               // Compare git_t type and not group name
+               if (grpinfo->gr_gid != userinfo->pw_gid) {
+                       mc_error("UID [%d] does not belong to 'users' group!", uid);
+                       return NULL;
+               }
+               snprintf(result_psswd, sizeof(result_psswd), "%s/.applications/dbspace/.media_controller.db", userinfo->pw_dir);
+       }
+
+       dir = strrchr(result_psswd, '/');
+       if(!dir)
+               return strdup(result_psswd);
+
+       //Control if db exist create otherwise
+       if(access(dir + 1, F_OK)) {
+               int ret;
+               mkdir(dir + 1, S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH);
+               ret = chown(dir + 1, uid, grpinfo->gr_gid);
+               if (ret == -1) {
+                       mc_debug("FAIL : chown %s %d.%d ", dir + 1, uid, grpinfo->gr_gid);
+                       mc_stderror("FAIL : chown");
+               }
+       }
+
+       result_psswd_rtn = strdup(result_psswd);
+
+       return result_psswd_rtn;
+}
+
 int mc_db_connect(void **handle)
 {
        int ret = MEDIA_CONTROLLER_ERROR_NONE;
@@ -176,7 +244,7 @@ int mc_db_connect(void **handle)
        mc_retvm_if(handle == NULL, MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER, "Handle is NULL");
 
        /*Connect DB*/
-       ret = db_util_open(MC_DB_NAME, &db_handle, DB_UTIL_REGISTER_HOOK_METHOD);
+       ret = db_util_open(__mc_get_db_name(tzplatform_getuid(TZ_USER_NAME)), &db_handle, DB_UTIL_REGISTER_HOOK_METHOD);
        if (SQLITE_OK != ret) {
                mc_error("error when db open");
                *handle = NULL;
index 6343a1e..b0d6f45 100755 (executable)
@@ -14,6 +14,8 @@
 * limitations under the License.
 */
 
+#include <tzplatform_config.h>
+
 #include "media_controller_private.h"
 
 #define MAX_RETRY_COUNT 3
@@ -290,6 +292,7 @@ int mc_ipc_send_message_to_server(mc_msg_type_e msg_type, const char *request_ms
        memset((void *)&send_msg, 0, sizeof(mc_comm_msg_s));
 
        send_msg.msg_type = msg_type;
+       send_msg.uid = tzplatform_getuid(TZ_USER_NAME);
        send_msg.msg_size = request_msg_size;
        strncpy(send_msg.msg, request_msg, sizeof(send_msg.msg) - 1);
 
index faf0c61..2e1eb7f 100755 (executable)
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <grp.h>
+#include <pwd.h>
+#include <tzplatform_config.h>
+#include <sys/stat.h>
 
-#include "media_controller_db_util.h"
 #include "media_controller_private.h"
+#include "media_controller_db_util.h"
+
+#define FAT_FILEPATH_LEN_MAX           4096    /* inc null */
+#define MC_FILE_PATH_LEN_MAX           FAT_FILEPATH_LEN_MAX             /**< File path max length (include file name) on file system */
 
 static int __mc_db_util_busy_handler(void *pData, int count)
 {
@@ -26,7 +36,64 @@ static int __mc_db_util_busy_handler(void *pData, int count)
        return 100 - count;
 }
 
-int mc_db_util_connect(void **handle)
+static char* __mc_get_db_name(uid_t uid)
+{
+       char result_psswd[MC_FILE_PATH_LEN_MAX];
+       char *result_psswd_rtn = NULL;
+       struct group *grpinfo = NULL;
+       char * dir = NULL;
+
+       memset(result_psswd, 0, sizeof(result_psswd));
+       if(uid == getuid())
+       {
+               strncpy(result_psswd, MC_DB_NAME, sizeof(result_psswd));
+               grpinfo = getgrnam("users");
+               if(grpinfo == NULL) {
+                       mc_error("getgrnam(users) returns NULL !");
+                       return NULL;
+               }
+       }
+       else
+       {
+               struct passwd *userinfo = getpwuid(uid);
+               if(userinfo == NULL) {
+                       mc_error("getpwuid(%d) returns NULL !", uid);
+                       return NULL;
+               }
+               grpinfo = getgrnam("users");
+               if(grpinfo == NULL) {
+                       mc_error("getgrnam(users) returns NULL !");
+                       return NULL;
+               }
+               // Compare git_t type and not group name
+               if (grpinfo->gr_gid != userinfo->pw_gid) {
+                       mc_error("UID [%d] does not belong to 'users' group!", uid);
+                       return NULL;
+               }
+               snprintf(result_psswd, sizeof(result_psswd), "%s/.applications/dbspace/.media_controller.db", userinfo->pw_dir);
+       }
+
+       dir = strrchr(result_psswd, '/');
+       if(!dir)
+               return strdup(result_psswd);
+
+       //Control if db exist create otherwise
+       if(access(dir + 1, F_OK)) {
+               int ret;
+               mkdir(dir + 1, S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH);
+               ret = chown(dir + 1, uid, grpinfo->gr_gid);
+               if (ret == -1) {
+                       mc_debug("FAIL : chown %s %d.%d ", dir + 1, uid, grpinfo->gr_gid);
+                       mc_stderror("FAIL : chown");
+               }
+       }
+
+       result_psswd_rtn = strdup(result_psswd);
+
+       return result_psswd_rtn;
+}
+
+int mc_db_util_connect(void **handle, uid_t uid)
 {
        int ret = MEDIA_CONTROLLER_ERROR_NONE;
        sqlite3 *db_handle = NULL;
@@ -34,7 +101,7 @@ int mc_db_util_connect(void **handle)
        mc_retvm_if(handle == NULL, MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER, "Handle is NULL");
 
        /*Connect DB*/
-       ret = db_util_open(MC_DB_NAME, &db_handle, DB_UTIL_REGISTER_HOOK_METHOD);
+       ret = db_util_open(__mc_get_db_name(uid), &db_handle, DB_UTIL_REGISTER_HOOK_METHOD);
        if (SQLITE_OK != ret) {
                mc_error("error when db open");
                *handle = NULL;
@@ -100,4 +167,3 @@ int mc_db_util_disconnect(void *handle)
 
        return MEDIA_CONTROLLER_ERROR_NONE;
 }
-
index f858a17..4f602fb 100755 (executable)
 #include <sqlite3.h>
 #include <tzplatform_config.h>
 
-#define MC_DB_NAME tzplatform_mkpath(TZ_SYS_DB, ".media_controller.db")
+#define MC_DB_NAME ".media_controller.db"
 
 #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);
+int mc_db_util_connect(void **handle, uid_t uid);
 int mc_db_util_update_db(void *handle, const char *sql_str);
 int mc_db_util_disconnect(void *handle);
 
index a5b0b3f..a7407d7 100755 (executable)
@@ -118,10 +118,8 @@ int mc_ipc_create_server_socket(mc_msg_port_type_e port, int *sock_fd)
        mc_debug("Listening...");
 
        /*change permission of sock file*/
-       if (chmod(MC_IPC_PATH, 0660) < 0)
+       if (chmod(MC_IPC_PATH, 0666) < 0)
                mc_stderror("chmod failed");
-       if (chown(MC_IPC_PATH, 200, 5000) < 0)
-               mc_stderror("chown failed");
 
        *sock_fd = sock;
 
index a17a073..15d5bb9 100755 (executable)
@@ -20,6 +20,7 @@
 #include <sys/un.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <tzplatform_config.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -29,8 +30,8 @@ extern "C" {
 #define MC_TIMEOUT_SEC_10                                      10              /**< Response from Server time out */
 #define MAX_MSG_SIZE                           4096*2
 #define MC_SOCK_NOT_ALLOCATE           -1
-#define MC_SOCK_ACTIVATION_PATH                "/var/run/mediacontroller/media_sa_controller"
-#define MC_IPC_PATH            "/var/run/mediacontroller/media_ipc_controller"
+#define MC_SOCK_ACTIVATION_PATH                "/var/run/media-controller/media_sa_controller"
+#define MC_IPC_PATH                                    "/var/run/media-controller/media_ipc_controller"
 #define MC_SERVER_CONNECTION_MSG                       "Connect"
 #define MC_SERVER_DISCONNECTION_MSG            "Disonnect"
 
@@ -56,6 +57,7 @@ typedef struct {
 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];
index 55e4905..79bbee8 100755 (executable)
@@ -92,6 +92,11 @@ gboolean _mc_read_service_request_tcp_socket(GIOChannel *src, GIOCondition condi
        }
 
        if (recv_msg.msg_type == MC_MSG_DB_UPDATE) {
+               /* Connect media controller DB*/
+               if(mc_db_util_connect(&(mc_svc_data->db_handle), recv_msg.uid) != MEDIA_CONTROLLER_ERROR_NONE) {
+                       mc_error("Failed to connect DB");
+                       goto ERROR;
+               }
                sql_query = strndup(recv_msg.msg, recv_msg.msg_size);
                if (sql_query != NULL) {
                        ret = mc_db_util_update_db(mc_svc_data->db_handle, sql_query);
@@ -103,6 +108,10 @@ gboolean _mc_read_service_request_tcp_socket(GIOChannel *src, GIOCondition condi
                } else {
                        send_msg = MEDIA_CONTROLLER_ERROR_OUT_OF_MEMORY;
                }
+               /* Disconnect DB*/
+               if(mc_db_util_disconnect(mc_svc_data->db_handle) != MEDIA_CONTROLLER_ERROR_NONE) {
+                       mc_error("Failed to disconnect DB");
+               }
        } else if (recv_msg.msg_type == MC_MSG_CLIENT_SET) {
                /* check privileage */
                ret = __mc_privilege_ask(client_sock, "mediacontroller::svc", "w");
@@ -220,13 +229,6 @@ gboolean mc_svc_thread(void *data)
                return FALSE;
        }
 
-       /* Connect Media DB*/
-       if (mc_db_util_connect(&(mc_svc_data->db_handle)) != MEDIA_CONTROLLER_ERROR_NONE) {
-               mc_error("Failed to connect DB");
-               close(sockfd);
-               return FALSE;
-       }
-
        /* Create list for command*/
        mc_svc_data->mc_svc_list = g_list_alloc();
        if (mc_svc_data->mc_svc_list == NULL) {
@@ -266,8 +268,6 @@ gboolean mc_svc_thread(void *data)
        g_io_channel_shutdown(channel,  FALSE, NULL);
        g_io_channel_unref(channel);
 
-       /* Disconnect DB*/
-       mc_db_util_disconnect(mc_svc_data->db_handle);
 
        if (mc_svc_data->mc_svc_list != NULL) {
                int i = 0;
index 941d405..2b2693d 100755 (executable)
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-#if 0
-#include <glib.h>
-#include <dlog.h>
-#include <media_controller_server.h>
-
-#define PACKAGE "MC_SERVER_TEST"
-
-/*===========================================================================================
-|                                             |
-|  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                      |
-|                                               |
-========================================================================================== */
-/*---------------------------------------------------------------------------
-|    GLOBAL VARIABLE DEFINITIONS:                     |
----------------------------------------------------------------------------*/
-
-GMainLoop *g_loop;
-
-/*---------------------------------------------------------------------------
-|    LOCAL CONSTANT DEFINITIONS:                      |
----------------------------------------------------------------------------*/
-
-/*---------------------------------------------------------------------------
-|    LOCAL VARIABLE DEFINITIONS:                      |
----------------------------------------------------------------------------*/
-
-static unsigned long long  duration = 0;
-/*---------------------------------------------------------------------------
-|    LOCAL FUNCTION PROTOTYPES:                       |
----------------------------------------------------------------------------*/
-
-void quit_program(void *mc_server)
-{
-       mc_server_destroy(mc_server);
-       mc_server = NULL;
-       g_main_loop_quit(g_loop);
-}
 
-static gboolean __func1(void *mc_server)
-{
-       int i = MEDIA_TITLE;
-
-       mc_server_set_playback_state(mc_server, MEDIA_PLAYBACK_STATE_PLAYING);
-       mc_server_set_playback_position(mc_server, duration);
-       mc_server_update_playback_info(mc_server);
-
-       for (; i <= MEDIA_PICTURE; ++i) {
-               mc_server_set_metadata(mc_server, (mc_meta_e)i, "META_VALUE");
-       }
-       mc_server_update_metadata(mc_server);
-       mc_server_update_shuffle_mode(mc_server, SHUFFLE_MODE_OFF);
-       mc_server_update_repeat_mode(mc_server, REPEAT_MODE_OFF);
-       g_usleep(4000);
-       duration += 4000;
-       return TRUE;
-}
-
-int main(int argc, char *argv[])
-{
-       mc_server_h mc_server = NULL;
-       int error = MEDIA_CONTROLLER_ERROR_NONE;
-
-       error = mc_server_create(&mc_server);
-       if (MEDIA_CONTROLLER_ERROR_NONE == error && mc_server != NULL) {
-               g_timeout_add_seconds(5, __func1, (void *)mc_server);
-
-               g_loop = g_main_loop_new(NULL, FALSE);
-               g_main_loop_run(g_loop);
-               quit_program(mc_server);
-       } else {
-               dlog_print(DLOG_INFO, PACKAGE, "mc_server_create: error %d ", error);
-       }
-
-       return error;
-}
-#else
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -627,5 +552,3 @@ int main(int argc, char **argv)
 
        return 0;
 }
-
-#endif