#include <sys/types.h>
#include <signal.h>
#include <grp.h>
+#include <fcntl.h>
#include <glib.h>
#include <gio/gio.h>
#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;
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);
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)
{
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);
return 0;
}
-void free_user_context(user_ctx* ctx)
+void free_user_context(user_ctx *ctx)
{
char **env = NULL;
int i = 0;
static int __fork_and_exec_with_args(char **argv, uid_t uid)
{
- user_ctx* user_context;
+ user_ctx *user_context;
GError *error = NULL;
gboolean ret;
int pid;
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);
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;
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;
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);
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);
" <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'/>"
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)
{
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)