refactor getsize sync function 25/105825/9
authorjongmyeongko <jongmyeong.ko@samsung.com>
Mon, 19 Dec 2016 14:10:32 +0000 (23:10 +0900)
committerjongmyeongko <jongmyeong.ko@samsung.com>
Wed, 21 Dec 2016 12:05:37 +0000 (21:05 +0900)
Submit with:
https://review.tizen.org/gerrit/#/c/105817/
https://review.tizen.org/gerrit/#/c/105823/
https://review.tizen.org/gerrit/#/c/105825/

Change-Id: I2b5a17199324a1f0ee6a2bac0f5adf8d077283f8
Signed-off-by: jongmyeongko <jongmyeong.ko@samsung.com>
include/pkgmgr-server.h
include/queue.h
org.tizen.pkgmgr.conf
src/pkgmgr-server.c
src/queue.c
src/request.c

index 530ca0d..e22bfeb 100644 (file)
@@ -65,6 +65,7 @@ enum request_type {
        REQUEST_TYPE_ENABLE_APP,
        REQUEST_TYPE_DISABLE_APP,
        REQUEST_TYPE_GETSIZE,
+       REQUEST_TYPE_GETSIZE_SYNC,
        REQUEST_TYPE_CLEARDATA,
        REQUEST_TYPE_CLEARCACHE,
        REQUEST_TYPE_ENABLE_GLOBAL_APP_FOR_UID,
index 27fd907..d89d78c 100644 (file)
 
 #include <sys/types.h>
 
+struct job_extra_info {
+       int getsize_fd;
+       char *getsize_fifo;
+       GIOChannel *getsize_io;
+};
+
 struct backend_job {
        uid_t target_uid;
        uid_t caller_uid;
@@ -31,6 +37,7 @@ struct backend_job {
        int backend_slot;
        char *backend_type;
        char *backend_path;
+       struct job_extra_info *extra;
 };
 
 int _is_queue_empty(int pos);
@@ -41,5 +48,6 @@ struct backend_job *_pop_queue(int pos);
 void _free_backend_job(struct backend_job *job);
 int _init_backend_queue(void);
 void _fini_backend_queue(void);
+void __free_extra_info(struct backend_job *job);
 
 #endif  // _QUEUE_H_
index e94bf6c..7ad7a4b 100644 (file)
@@ -25,6 +25,7 @@
                <check send_destination="org.tizen.pkgmgr" send_interface="org.tizen.pkgmgr" send_member="activate" privilege="http://tizen.org/privilege/packagemanager.admin"/>
                <check send_destination="org.tizen.pkgmgr" send_interface="org.tizen.pkgmgr" send_member="deactivate" privilege="http://tizen.org/privilege/packagemanager.admin"/>
                <check send_destination="org.tizen.pkgmgr" send_interface="org.tizen.pkgmgr" send_member="getsize" privilege="http://tizen.org/privilege/packagemanager.info"/>
+               <check send_destination="org.tizen.pkgmgr" send_interface="org.tizen.pkgmgr" send_member="getsize_sync" privilege="http://tizen.org/privilege/packagemanager.info"/>
                <check send_destination="org.tizen.pkgmgr" send_interface="org.tizen.pkgmgr" send_member="clearcache" privilege="http://tizen.org/privilege/packagemanager.clearcache"/>
                <check send_destination="org.tizen.pkgmgr" send_interface="org.tizen.pkgmgr" send_member="kill" privilege="http://tizen.org/privilege/packagemanager.admin"/>
                <check send_destination="org.tizen.pkgmgr" send_interface="org.tizen.pkgmgr" send_member="check" privilege="http://tizen.org/privilege/packagemanager.info"/>
index c3d33d1..d390f90 100644 (file)
@@ -32,6 +32,7 @@
 #include <sys/types.h>
 #include <signal.h>
 #include <grp.h>
+#include <fcntl.h>
 
 #include <glib.h>
 #include <gio/gio.h>
@@ -59,6 +60,7 @@
 #define EXT_STORAGE_APPDATA_GROUP 10002
 #define MEDIA_STORAGE_GROUP 10502
 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+#define MAX_LONGLONG_LENGTH 32
 
 typedef struct  {
        char **env;
@@ -89,7 +91,7 @@ static int pipe_sig[2];
 static GIOChannel *pipe_io;
 static guint pipe_wid;
 static GHashTable *backend_info_table;
-static GMainLoop *mainloop = NULL;
+static GMainLoop *mainloop;
 
 static int __check_backend_status_for_exit(void);
 static int __check_queue_status_for_exit(void);
@@ -116,6 +118,67 @@ static void __set_backend_free(int position)
        backend_busy = backend_busy & ~(1 << position);
 }
 
+static gboolean getsize_io_handler(GIOChannel *io, GIOCondition cond,
+               gpointer data)
+{
+       GError *err = NULL;
+       GIOStatus s;
+       gsize len;
+       char buf[MAX_LONGLONG_LENGTH];
+       long long result = 0;
+       struct backend_job *job = (struct backend_job *)data;
+
+       s = g_io_channel_read_chars(io, (gchar *)buf, sizeof(buf), &len, &err);
+       if (s != G_IO_STATUS_NORMAL) {
+               ERR("getsize fd read failed: %s", err->message);
+               g_error_free(err);
+               result = -1;
+       } else {
+               if (strlen(buf) == 0) {
+                       ERR("empty result");
+                       result = -1;
+               } else {
+                       result = atoll(buf);
+               }
+       }
+
+       _return_value_to_caller(job->req_id, g_variant_new("(ix)",
+               (result < 0) ? PKGMGR_R_ERROR : PKGMGR_R_OK, result));
+
+       unlink(job->extra->getsize_fifo);
+       free(job->extra->getsize_fifo);
+       job->extra->getsize_fifo = NULL;
+
+       return FALSE;
+}
+
+static int __setup_size_info_io(struct backend_job *job)
+{
+       guint getsize_wid;
+
+       job->extra->getsize_fd = open(job->extra->getsize_fifo,
+               O_RDONLY | O_NONBLOCK);
+       if (job->extra->getsize_fd < 0) {
+               ERR("failed to open the fifo(%s), errno(%d)",
+                       job->extra->getsize_fifo, errno);
+               return -1;
+       }
+
+       job->extra->getsize_io = g_io_channel_unix_new(job->extra->getsize_fd);
+       if (!job->extra->getsize_io)
+               return -1;
+       g_io_channel_set_encoding(job->extra->getsize_io, NULL, NULL);
+       g_io_channel_set_buffered(job->extra->getsize_io, FALSE);
+       getsize_wid = g_io_add_watch(job->extra->getsize_io,
+               G_IO_IN, getsize_io_handler, job);
+       if (!getsize_wid) {
+               ERR("failed to add io watch");
+               return -1;
+       }
+
+       return 0;
+}
+
 static gboolean pipe_io_handler(GIOChannel *io, GIOCondition cond,
                gpointer data)
 {
@@ -151,6 +214,14 @@ static gboolean pipe_io_handler(GIOChannel *io, GIOCondition cond,
                DBG("backend[%s] exit", job->backend_type);
        }
 
+       if (job->extra) {
+               if (job->extra->getsize_fifo) {
+                       ERR("invalid backend close");
+                       _return_value_to_caller(job->req_id,
+                               g_variant_new("(ix)", PKGMGR_R_ERROR, -1));
+               }
+       }
+
        g_hash_table_remove(backend_info_table, (gconstpointer)info.pid);
        g_idle_add(queue_job, NULL);
 
@@ -356,7 +427,7 @@ static int __pkgcmd_app_cb(const pkgmgrinfo_appinfo_h handle, void *user_data)
        return 0;
 }
 
-void free_user_context(user_ctxctx)
+void free_user_context(user_ctx *ctx)
 {
        char **env = NULL;
        int i = 0;
@@ -542,7 +613,7 @@ void __set_environment(gpointer user_data)
 
 static int __fork_and_exec_with_args(char **argv, uid_t uid)
 {
-       user_ctxuser_context;
+       user_ctx *user_context;
        GError *error = NULL;
        gboolean ret;
        int pid;
@@ -559,6 +630,8 @@ static int __fork_and_exec_with_args(char **argv, uid_t uid)
        if (ret != TRUE) {
                ERR("Failed to excute backend: %s", error->message);
                g_error_free(error);
+               free_user_context(user_context);
+               return -1;
        }
 
        free_user_context(user_context);
@@ -1033,6 +1106,59 @@ static int __process_getsize(struct backend_job *job)
        return pid;
 }
 
+static int __process_getsize_sync(struct backend_job *job)
+{
+       static const char backend_cmd[] = "/usr/bin/pkg_getsize";
+       char **argv;
+       char args[MAX_PKG_ARGS_LEN];
+       char fifo_path[PATH_MAX];
+       int pid;
+
+       snprintf(fifo_path, sizeof(fifo_path), "/tmp/pkgmgr/%s",
+                       job->req_id);
+
+       job->extra = calloc(1, sizeof(struct job_extra_info));
+       if (!job->extra) {
+               ERR("memory alloc failed");
+               goto error;
+       }
+
+       job->extra->getsize_fifo = strdup(fifo_path);
+       if (!job->extra->getsize_fifo) {
+               ERR("out of memory");
+               goto error;
+       }
+
+       if (mkfifo(job->extra->getsize_fifo, 0600) < 0) {
+               ERR("failed to mkfifo");
+               goto error;
+       }
+
+       snprintf(args, sizeof(args), "%s %s %s %d -k %s -u %d --sync",
+                       backend_cmd, job->pkgid, job->args, job->caller_uid,
+                       job->req_id, job->target_uid);
+       argv = __generate_argv(args);
+       pid = __fork_and_exec_with_args(argv, APPFW_UID);
+
+       g_strfreev(argv);
+
+       if (pid < 0) {
+               ERR("failed to execute backend");
+               goto error;
+       }
+       if (__setup_size_info_io(job) < 0) {
+               ERR("failed to setup io handler");
+               goto error;
+       }
+
+       return pid;
+
+error:
+       _return_value_to_caller(job->req_id,
+               g_variant_new("(ix)", PKGMGR_R_ERROR, -1));
+       return -1;
+}
+
 static int __process_cleardata(struct backend_job *job)
 {
        char *backend_cmd;
@@ -1329,6 +1455,18 @@ static int __process_set_app_label(struct backend_job *job)
        return ret;
 }
 
+static int __post_process(int ret, int x, struct backend_job *job)
+{
+       if (ret < 0) {
+               __set_backend_free(x);
+               _free_backend_job(job);
+       } else {
+               g_hash_table_insert(backend_info_table, (gpointer)ret,
+                               (gpointer)job);
+       }
+       return 0;
+}
+
 gboolean queue_job(void *data)
 {
        struct backend_job *job = NULL;
@@ -1372,56 +1510,41 @@ gboolean queue_job(void *data)
        case REQUEST_TYPE_INSTALL:
                __set_backend_busy(x);
                ret = __process_install(job);
-               g_hash_table_insert(backend_info_table, (gpointer)ret,
-                               (gpointer)job);
+               __post_process(ret, x, job);
                break;
        case REQUEST_TYPE_MOUNT_INSTALL:
                __set_backend_busy(x);
                ret = __process_mount_install(job);
-               g_hash_table_insert(backend_info_table, (gpointer)ret,
-                               (gpointer)job);
+               __post_process(ret, x, job);
                break;
        case REQUEST_TYPE_REINSTALL:
                __set_backend_busy(x);
                ret = __process_reinstall(job);
-               g_hash_table_insert(backend_info_table, (gpointer)ret,
-                               (gpointer)job);
+               __post_process(ret, x, job);
                break;
        case REQUEST_TYPE_UNINSTALL:
                __set_backend_busy(x);
                ret = __process_uninstall(job);
-               g_hash_table_insert(backend_info_table, (gpointer)ret,
-                               (gpointer)job);
+               __post_process(ret, x, job);
                break;
        case REQUEST_TYPE_MOVE:
                __set_backend_busy(x);
                ret = __process_move(job);
-               g_hash_table_insert(backend_info_table, (gpointer)ret,
-                               (gpointer)job);
+               __post_process(ret, x, job);
                break;
        case REQUEST_TYPE_ENABLE_PKG:
                __set_backend_busy(x);
                ret = __process_enable_pkg(job);
-               if (ret == -1) {
+               if (ret < 0)
                        _send_fail_signal(job);
-                       __set_backend_free(x);
-                       _free_backend_job(job);
-               } else {
-                       g_hash_table_insert(backend_info_table, (gpointer)ret,
-                                       (gpointer)job);
-               }
+               __post_process(ret, x, job);
                break;
        case REQUEST_TYPE_DISABLE_PKG:
                __set_backend_busy(x);
                ret = __process_disable_pkg(job);
-               if (ret == -1) {
+               if (ret < 0)
                        _send_fail_signal(job);
-                       __set_backend_free(x);
-                       _free_backend_job(job);
-               } else {
-                       g_hash_table_insert(backend_info_table, (gpointer)ret,
-                                       (gpointer)job);
-               }
+               __post_process(ret, x, job);
                break;
        case REQUEST_TYPE_ENABLE_APP:
                ret = __process_enable_app(job);
@@ -1434,20 +1557,24 @@ gboolean queue_job(void *data)
        case REQUEST_TYPE_GETSIZE:
                __set_backend_busy(x);
                ret = __process_getsize(job);
-               g_hash_table_insert(backend_info_table, (gpointer)ret,
-                               (gpointer)job);
+               __post_process(ret, x, job);
+               break;
+       case REQUEST_TYPE_GETSIZE_SYNC:
+               __set_backend_busy(x);
+               ret = __process_getsize_sync(job);
+               if (ret < 0)
+                       __free_extra_info(job);
+               __post_process(ret, x, job);
                break;
        case REQUEST_TYPE_CLEARDATA:
                __set_backend_busy(x);
                ret = __process_cleardata(job);
-               g_hash_table_insert(backend_info_table, (gpointer)ret,
-                               (gpointer)job);
+               __post_process(ret, x, job);
                break;
        case REQUEST_TYPE_CLEARCACHE:
                __set_backend_busy(x);
                ret = __process_clearcache(job);
-               g_hash_table_insert(backend_info_table, (gpointer)ret,
-                               (gpointer)job);
+               __post_process(ret, x, job);
                break;
        case REQUEST_TYPE_ENABLE_GLOBAL_APP_FOR_UID:
                ret = __process_enable_global_app_for_uid(job);
index 11e6ace..68b0476 100644 (file)
@@ -159,8 +159,25 @@ static gboolean __str_equal(gconstpointer v1, gconstpointer v2)
        return strcasecmp(str1, str2) == 0;
 }
 
+void __free_extra_info(struct backend_job *job)
+{
+       if (job->extra) {
+               if (job->extra->getsize_io)
+                       g_io_channel_unref(job->extra->getsize_io);
+               if (job->extra->getsize_fd)
+                       close(job->extra->getsize_fd);
+               if (job->extra->getsize_fifo) {
+                       unlink(job->extra->getsize_fifo);
+                       free(job->extra->getsize_fifo);
+               }
+               free(job->extra);
+               job->extra = NULL;
+       }
+}
+
 void _free_backend_job(struct backend_job *job)
 {
+       __free_extra_info(job);
        free(job->req_id);
        free(job->pkgid);
        free(job->appid);
index 4db0f6d..fce8210 100644 (file)
@@ -97,6 +97,13 @@ static const char instropection_xml[] =
        "      <arg type='i' name='ret' direction='out'/>"
        "      <arg type='s' name='reqkey' direction='out'/>"
        "    </method>"
+       "    <method name='getsize_sync'>"
+       "      <arg type='u' name='uid' direction='in'/>"
+       "      <arg type='s' name='pkgid' direction='in'/>"
+       "      <arg type='i' name='get_type' direction='in'/>"
+       "      <arg type='i' name='ret' direction='out'/>"
+       "      <arg type='x' name='size_info' direction='out'/>"
+       "    </method>"
        "    <method name='cleardata'>"
        "      <arg type='u' name='uid' direction='in'/>"
        "      <arg type='s' name='pkgid' direction='in'/>"
@@ -914,6 +921,45 @@ static int __handle_request_getsize(uid_t caller_uid,
        return 0;
 }
 
+static int __handle_request_getsize_sync(uid_t caller_uid,
+               GDBusMethodInvocation *invocation, GVariant *parameters)
+{
+       uid_t target_uid = (uid_t)-1;
+       char *pkgid = NULL;
+       int get_type = -1;
+       char *reqkey;
+       char buf[4];
+
+       g_variant_get(parameters, "(u&si)", &target_uid, &pkgid, &get_type);
+       if (target_uid == (uid_t)-1 || pkgid == NULL || get_type == -1) {
+               g_dbus_method_invocation_return_value(invocation,
+                               g_variant_new("(is)", PKGMGR_R_ECOMM, ""));
+               return -1;
+       }
+
+       reqkey = __generate_reqkey(pkgid);
+       if (reqkey == NULL) {
+               g_dbus_method_invocation_return_value(invocation,
+                               g_variant_new("(is)", PKGMGR_R_ENOMEM, ""));
+               return -1;
+       }
+
+       snprintf(buf, sizeof(buf), "%d", get_type);
+       if (_push_queue(target_uid, caller_uid, reqkey, REQUEST_TYPE_GETSIZE_SYNC,
+                               "pkgtool", pkgid, buf)) {
+               g_dbus_method_invocation_return_value(invocation,
+                               g_variant_new("(is)", PKGMGR_R_ESYSTEM, ""));
+               free(reqkey);
+               return -1;
+       }
+
+       if (!g_hash_table_insert(req_table, (gpointer)reqkey,
+                               (gpointer)invocation))
+               ERR("reqkey already exists");
+
+       return 0;
+}
+
 static int __handle_request_cleardata(uid_t caller_uid,
                GDBusMethodInvocation *invocation, GVariant *parameters)
 {
@@ -1442,6 +1488,8 @@ static void __handle_method_call(GDBusConnection *connection,
                ret = __handle_request_disable_pkgs(uid, invocation, parameters);
        else if (g_strcmp0(method_name, "getsize") == 0)
                ret = __handle_request_getsize(uid, invocation, parameters);
+       else if (g_strcmp0(method_name, "getsize_sync") == 0)
+               ret = __handle_request_getsize_sync(uid, invocation, parameters);
        else if (g_strcmp0(method_name, "clearcache") == 0)
                ret = __handle_request_clearcache(uid, invocation, parameters);
        else if (g_strcmp0(method_name, "enable_app") == 0)