4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>,
7 * Jaeho Lee <jaeho81.lee@samsung.com>, Shobhit Srivastava <shobhit.s@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
29 #include <sys/types.h>
33 #include <sys/types.h>
40 #include <pkgmgr-info.h>
41 #include <pkgmgr/pkgmgr_parser.h>
42 #include <cynara-client.h>
43 #include <cynara-creds-gdbus.h>
44 #include <cynara-session.h>
45 #include <tzplatform_config.h>
47 #include "pkgmgr_installer.h"
48 #include "pkgmgr-server.h"
50 #include "comm_config.h"
51 #include "package-manager.h"
54 #define NO_MATCHING_FILE 11
57 #define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)
59 static int backend_flag = 0; /* 0 means that backend process is not running */
69 8 bit value to represent maximum 8 backends.
70 Each bit position corresponds to a queue slot which
71 is dynamically determined.
73 char backend_busy = 0;
75 8 bit value to represent quiet mode operation for maximum 8 backends
77 Each bit position corresponds to a queue slot which
78 is dynamically determined.
80 char backend_mode = 63; /*00111111*/
81 extern int num_of_backends;
83 struct signal_info_t {
88 static int pipe_sig[2];
89 static GIOChannel *pipe_io;
90 static guint pipe_wid;
93 extern queue_info_map *start;
95 static cynara *p_cynara;
97 GMainLoop *mainloop = NULL;
102 OPERATION_INSTALL = 0,
109 static int __check_backend_status_for_exit(void);
110 static int __check_queue_status_for_exit(void);
111 static int __is_backend_busy(int position);
112 static void __set_backend_busy(int position);
113 static void __set_backend_free(int position);
114 static void __set_backend_mode(int position);
115 static void __unset_backend_mode(int position);
116 static void sighandler(int signo);
117 static int __get_position_from_pkg_type(char *pkgtype);
119 gboolean queue_job(void *data);
120 gboolean exit_server(void *data);
122 /* To check whether a particular backend is free/busy*/
123 static int __is_backend_busy(int position)
125 return backend_busy & 1<<position;
127 /*To set a particular backend as busy*/
128 static void __set_backend_busy(int position)
130 backend_busy = backend_busy | 1<<position;
132 /*To set a particular backend as free */
133 static void __set_backend_free(int position)
135 backend_busy = backend_busy & ~(1<<position);
137 /*To set a particular backend mode as quiet*/
138 static void __set_backend_mode(int position)
140 backend_mode = backend_mode | 1<<position;
142 /*To unset a particular backend mode */
143 static void __unset_backend_mode(int position)
145 backend_mode = backend_mode & ~(1<<position);
148 static int __is_global(uid_t uid)
150 return (uid == OWNER_ROOT || uid == GLOBAL_USER) ? 1 : 0;
153 static const char *__get_recovery_file_path(uid_t uid)
157 if (!__is_global(uid))
158 tzplatform_set_user(uid);
160 path = tzplatform_getenv(__is_global(uid)
161 ? TZ_SYS_RW_PACKAGES : TZ_USER_PACKAGES);
163 tzplatform_reset_user();
168 static void __set_recovery_mode(uid_t uid, char *pkgid, char *pkg_type)
170 char recovery_file[MAX_PKG_NAME_LEN] = { 0, };
171 char buffer[MAX_PKG_NAME_LEN] = { 0 };
172 char *pkgid_tmp = NULL;
173 FILE *rev_file = NULL;
176 DBG("pkgid is null\n");
180 /*if pkgid has a "/"charactor, that is a path name for installation, then extract pkgid from absolute path*/
181 if (strstr(pkgid, "/")) {
182 pkgid_tmp = strrchr(pkgid, '/') + 1;
183 if (pkgid_tmp == NULL) {
184 DBG("pkgid_tmp[%s] is null\n", pkgid);
187 snprintf(recovery_file, sizeof(recovery_file), "%s/%s", __get_recovery_file_path(uid), pkgid_tmp);
189 snprintf(recovery_file, sizeof(recovery_file), "%s/%s", __get_recovery_file_path(uid), pkgid);
192 rev_file = fopen(recovery_file, "w");
193 if (rev_file== NULL) {
194 DBG("rev_file[%s] is null\n", recovery_file);
198 snprintf(buffer, MAX_PKG_NAME_LEN, "pkgid : %s\n", pkgid);
199 fwrite(buffer, sizeof(char), strlen(buffer), rev_file);
204 static void __unset_recovery_mode(uid_t uid, char *pkgid, char *pkg_type)
207 char recovery_file[MAX_PKG_NAME_LEN] = { 0, };
208 char *pkgid_tmp = NULL;
211 DBG("pkgid is null\n");
215 /*if pkgid has a "/"charactor, that is a path name for installation, then extract pkgid from absolute path*/
216 if (strstr(pkgid, "/")) {
217 pkgid_tmp = strrchr(pkgid, '/') + 1;
218 if (pkgid_tmp == NULL) {
219 DBG("pkgid_tmp[%s] is null\n", pkgid);
222 snprintf(recovery_file, sizeof(recovery_file), "%s/%s", __get_recovery_file_path(uid), pkgid_tmp);
224 snprintf(recovery_file, sizeof(recovery_file), "%s/%s", __get_recovery_file_path(uid), pkgid);
227 ret = remove(recovery_file);
229 DBG("remove recovery_file[%s] fail\n", recovery_file);
232 #define PRIVILEGE_PACKAGEMANAGER_ADMIN "http://tizen.org/privilege/packagemanager.admin"
233 #define PRIVILEGE_PACKAGEMANAGER_INFO "http://tizen.org/privilege/packagemanager.info"
234 #define PRIVILEGE_PACKAGEMANAGER_CLEARCACHE "http://tizen.org/privilege/packagemanager.clearcache"
235 #define PRIVILEGE_PACKAGEMANAGER_NONE "NONE"
237 static const char *__convert_req_type_to_privilege(int req_type)
240 case COMM_REQ_TO_INSTALLER:
241 case COMM_REQ_TO_ACTIVATOR:
242 case COMM_REQ_TO_CLEARER:
243 case COMM_REQ_TO_MOVER:
244 case COMM_REQ_KILL_APP:
245 return PRIVILEGE_PACKAGEMANAGER_ADMIN;
246 case COMM_REQ_GET_SIZE:
247 case COMM_REQ_CHECK_APP:
248 return PRIVILEGE_PACKAGEMANAGER_INFO;
249 case COMM_REQ_CLEAR_CACHE_DIR:
250 return PRIVILEGE_PACKAGEMANAGER_CLEARCACHE;
251 case COMM_REQ_CANCEL:
253 return PRIVILEGE_PACKAGEMANAGER_NONE;
257 static int __check_privilege_by_cynara(const char *client, const char *session, const char *user, int req_type)
260 const char *privilege;
261 char buf[BUFMAX] = {0, };
263 privilege = __convert_req_type_to_privilege(req_type);
264 if (!strcmp(privilege, PRIVILEGE_PACKAGEMANAGER_NONE))
267 ret = cynara_check(p_cynara, client, session, user, privilege);
269 case CYNARA_API_ACCESS_ALLOWED:
270 DBG("%s(%s) from user %s privilege %s allowed", client, session, user, privilege);
272 case CYNARA_API_ACCESS_DENIED:
273 ERR("%s(%s) from user %s privilege %s denied", client, session, user, privilege);
276 cynara_strerror(ret, buf, BUFMAX);
277 ERR("cynara_check failed: %s", buf);
282 static int __get_position_from_pkg_type(char *pkgtype)
287 for(i = 0; i < entries; i++)
289 if (!strncmp(ptr->pkgtype, pkgtype, MAX_PKG_TYPE_LEN))
290 return ptr->queue_slot;
298 static void send_fail_signal(char *pname, char *ptype, char *args)
300 DBG("send_fail_signal start\n");
305 pkgmgr_installer *pi;
306 pi = pkgmgr_installer_new();
308 DBG("Failure in creating the pkgmgr_installer object");
311 ret_parse = g_shell_parse_argv(args,
312 &argcp, &argvp, &gerr);
313 if (FALSE == ret_parse) {
314 DBG("Failed to split args: %s", args);
315 DBG("messsage: %s", gerr->message);
316 pkgmgr_installer_free(pi);
320 pkgmgr_installer_receive_request(pi, argcp, argvp);
321 pkgmgr_installer_send_signal(pi, ptype, pname, "end", "fail");
322 pkgmgr_installer_free(pi);
326 static gboolean pipe_io_handler(GIOChannel *io, GIOCondition cond, gpointer data)
332 struct signal_info_t info;
333 backend_info *ptr = begin;
335 s = g_io_channel_read_chars(io, (gchar *)&info, sizeof(struct signal_info_t), &len, &err);
336 if (s != G_IO_STATUS_NORMAL) {
337 ERR("Signal pipe read failed: %s", err->message);
342 for (x = 0; x < num_of_backends; x++, ptr++) {
343 if (ptr && ptr->pid == info.pid)
347 if (x == num_of_backends) {
348 ERR("Unknown child exit");
352 __set_backend_free(x);
353 __set_backend_mode(x);
354 __unset_recovery_mode(ptr->uid, ptr->pkgid, ptr->pkgtype);
355 if (WIFSIGNALED(info.status) || WEXITSTATUS(info.status)) {
356 send_fail_signal(ptr->pkgid, ptr->pkgtype, ptr->args);
357 DBG("backend[%s] exit with error", ptr->pkgtype);
359 DBG("backend[%s] exit", ptr->pkgtype);
362 g_idle_add(queue_job, NULL);
367 static int __init_backend_info(void)
371 /*Allocate memory for holding pid, pkgtype and pkgid*/
372 ptr = (backend_info*)calloc(num_of_backends, sizeof(backend_info));
374 DBG("Malloc Failed\n");
379 if (pipe(pipe_sig)) {
380 ERR("create pipe failed");
384 pipe_io = g_io_channel_unix_new(pipe_sig[0]);
385 g_io_channel_set_encoding(pipe_io, NULL, NULL);
386 g_io_channel_set_buffered(pipe_io, FALSE);
387 pipe_wid = g_io_add_watch(pipe_io, G_IO_IN, pipe_io_handler, NULL);
392 static void __fini_backend_info(void)
394 g_source_remove(pipe_wid);
395 g_io_channel_unref(pipe_io);
399 /*Free backend info */
403 static void sighandler(int signo)
405 struct signal_info_t info;
407 info.pid = waitpid(-1, &info.status, WNOHANG);
408 if (write(pipe_sig[1], &info, sizeof(struct signal_info_t)) < 0)
409 ERR("failed to write result: %s", strerror(errno));
412 static int __register_signal_handler(void)
414 static int sig_reg = 0;
415 struct sigaction act;
420 act.sa_handler = sighandler;
421 sigemptyset(&act.sa_mask);
422 act.sa_flags = SA_NOCLDSTOP;
423 if (sigaction(SIGCHLD, &act, NULL) < 0) {
424 ERR("signal: SIGCHLD failed\n");
428 g_timeout_add_seconds(2, exit_server, NULL);
434 void req_cb(void *cb_data, uid_t uid, const char *req_id, const int req_type,
435 const char *pkg_type, const char *pkgid, const char *args,
436 const char *client, const char *session, const char *user, int *ret)
440 DBG(">> in callback >> Got request: [%s] [%d] [%s] [%s] [%s] [%s] [%s] [%s]",
441 req_id, req_type, pkg_type, pkgid, args, client, session, user);
443 pm_dbus_msg *item = calloc(1, sizeof(pm_dbus_msg));
444 memset(item, 0x00, sizeof(pm_dbus_msg));
446 strncpy(item->req_id, req_id, sizeof(item->req_id) - 1);
447 item->req_type = req_type;
448 strncpy(item->pkg_type, pkg_type, sizeof(item->pkg_type) - 1);
449 strncpy(item->pkgid, pkgid, sizeof(item->pkgid) - 1);
450 strncpy(item->args, args, sizeof(item->args) - 1);
452 /* uid equals to GLOBALUSER means that the installation or action is made at Global level.
453 * At this time, we are not able to check the credentials of this dbus message (due to gdbus API to implement the pkgmgr-server)
454 * So we cannot check if the user that makes request has permisssion to do it.
455 * Note theses CAPI could be used by deamon (user is root or system user) or web/native API framework (user id is one of regular users)
456 * In consequence a bug is filed :
458 * Logic has to be implmemented:
459 * RUID means the id of the user that make the request (retreived from credential of the message)
460 * UID is the uid in argument of the request
462 * if RUID == UID & UID is regular user == TRUE ==> Granted
463 * if UID == GLOBAL_USER & RUID is ADMIN == TRUE ==> Granted
464 * if RUID == (ROOT or System USER) & UID is Regular USER ==> Granted
465 * if UID != Regular USER & UID != GLOBAL USER == TRUE ==> NOT GRANTED
466 * if RUID == Regular USER & UID != RUID == True ==> NOT GRANTED
469 if (__register_signal_handler()) {
470 ERR("failed to register signal handler");
471 *ret = COMM_RET_ERROR;
474 g_idle_add(queue_job, NULL);
476 DBG("req_type=(%d) backend_flag=(%d)\n", req_type, backend_flag);
478 if (__check_privilege_by_cynara(client, session, user, item->req_type)) {
479 *ret = PKGMGR_R_EPRIV;
483 switch (item->req_type) {
484 case COMM_REQ_TO_INSTALLER:
486 if (_pm_queue_push(item)) {
487 ERR("failed to push queue item");
488 *ret = COMM_RET_ERROR;
491 p = __get_position_from_pkg_type(item->pkg_type);
492 __set_backend_mode(p);
497 case COMM_REQ_TO_ACTIVATOR:
498 /* In case of activate, there is no popup */
499 if (_pm_queue_push(item)) {
500 ERR("failed to push queue item");
501 *ret = COMM_RET_ERROR;
504 p = __get_position_from_pkg_type(item->pkg_type);
505 __set_backend_mode(p);
511 case COMM_REQ_TO_CLEARER:
512 /* In case of clearer, there is no popup */
513 if (_pm_queue_push(item)) {
514 ERR("failed to push queue item");
515 *ret = COMM_RET_ERROR;
518 p = __get_position_from_pkg_type(item->pkg_type);
519 /*the backend shows the success/failure popup
520 so this request is non quiet*/
521 __unset_backend_mode(p);
527 case COMM_REQ_TO_MOVER:
528 /* In case of mover, there is no popup */
529 if (_pm_queue_push(item)) {
530 ERR("failed to push queue item");
531 *ret = COMM_RET_ERROR;
534 p = __get_position_from_pkg_type(item->pkg_type);
535 /*the backend shows the success/failure popup
536 so this request is non quiet*/
537 __unset_backend_mode(p);
542 case COMM_REQ_CANCEL:
543 _pm_queue_delete(item);
544 p = __get_position_from_pkg_type(item->pkg_type);
545 __unset_backend_mode(p);
549 case COMM_REQ_GET_SIZE:
550 if (_pm_queue_push(item)) {
551 ERR("failed to push queue item");
552 *ret = COMM_RET_ERROR;
555 p = __get_position_from_pkg_type(item->pkg_type);
556 __set_backend_mode(p);
562 case COMM_REQ_CHECK_APP:
563 case COMM_REQ_KILL_APP:
564 /* In case of activate, there is no popup */
565 if (_pm_queue_push(item)) {
566 ERR("failed to push queue item");
567 *ret = COMM_RET_ERROR;
570 p = __get_position_from_pkg_type(item->pkg_type);
571 __set_backend_mode(p);
577 case COMM_REQ_CLEAR_CACHE_DIR:
578 if (_pm_queue_push(item)) {
579 ERR("failed to push queue item");
580 *ret = COMM_RET_ERROR;
583 p = __get_position_from_pkg_type(item->pkg_type);
584 __set_backend_mode(p);
590 DBG("Check your request..\n");
591 *ret = COMM_RET_ERROR;
595 if (*ret != COMM_RET_OK) {
596 DBG("Failed to handle request %s %s\n",item->pkg_type, item->pkgid);
597 pkgmgr_installer *pi;
603 pi = pkgmgr_installer_new();
605 DBG("Failure in creating the pkgmgr_installer object");
610 ret_parse = g_shell_parse_argv(args, &argcp, &argvp, &gerr);
611 if (FALSE == ret_parse) {
612 DBG("Failed to split args: %s", args);
613 DBG("messsage: %s", gerr->message);
614 pkgmgr_installer_free(pi);
619 pkgmgr_installer_receive_request(pi, argcp, argvp);
621 pkgmgr_installer_send_signal(pi, item->pkg_type,
625 pkgmgr_installer_free(pi);
631 static int __check_backend_status_for_exit(void)
634 for(i = 0; i < num_of_backends; i++)
636 if (!__is_backend_busy(i))
644 static int __check_queue_status_for_exit(void)
646 pm_queue_data *head[MAX_QUEUE_NUM] = {NULL,};
647 queue_info_map *ptr = NULL;
652 for(i = 0; i < entries; i++)
654 if (ptr->queue_slot <= slot) {
660 slot = ptr->queue_slot;
665 for(i = 0; i < num_of_backends; i++)
675 gboolean exit_server(void *data)
677 DBG("exit_server Start\n");
678 if (__check_backend_status_for_exit() &&
679 __check_queue_status_for_exit()) {
680 if (!getenv("PMS_STANDALONE")) {
681 g_main_loop_quit(mainloop);
688 static int __pkgcmd_read_proc(const char *path, char *buf, int size)
692 if (buf == NULL || path == NULL)
694 fd = open(path, O_RDONLY);
697 ret = read(fd, buf, size - 1);
707 static int __pkgcmd_find_pid_by_cmdline(const char *dname,
708 const char *cmdline, const char *apppath)
712 if (strcmp(cmdline, apppath) == 0) {
714 if (pid != getpgid(pid))
720 static int __pkgcmd_proc_iter_kill_cmdline(const char *apppath, int option)
723 struct dirent *dentry;
726 char buf[1024] = {'\0'};
729 dp = opendir("/proc");
734 while ((dentry = readdir(dp)) != NULL) {
735 if (!isdigit(dentry->d_name[0]))
738 snprintf(buf, sizeof(buf), "/proc/%s/cmdline", dentry->d_name);
739 ret = __pkgcmd_read_proc(buf, buf, sizeof(buf));
743 pid = __pkgcmd_find_pid_by_cmdline(dentry->d_name, buf, apppath);
754 if (killpg(pgid, SIGKILL) < 0) {
766 static void __make_pid_info_file(char *req_key, int pid)
770 char buf[MAX_PKG_TYPE_LEN] = {0};
771 char info_file[PATH_MAX] = {'\0'};
776 snprintf(info_file, PATH_MAX, "/tmp/%s", req_key);
778 DBG("info_path(%s)", info_file);
779 file = fopen(info_file, "w");
781 ERR("Couldn't open the file(%s)", info_file);
785 snprintf(buf, MAX_PKG_TYPE_LEN, "%d\n", pid);
786 fwrite(buf, 1, strlen(buf), file);
794 static int __pkgcmd_app_cb(const pkgmgrinfo_appinfo_h handle, void *user_data)
801 if (handle == NULL) {
802 perror("appinfo handle is NULL\n");
805 ret = pkgmgrinfo_appinfo_get_exec(handle, &exec);
807 perror("Failed to get app exec path\n");
810 ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgid);
812 perror("Failed to get pkgid\n");
816 if (strcmp(user_data, "kill") == 0)
817 pid = __pkgcmd_proc_iter_kill_cmdline(exec, 1);
818 else if(strcmp(user_data, "check") == 0)
819 pid = __pkgcmd_proc_iter_kill_cmdline(exec, 0);
821 __make_pid_info_file(pkgid, pid);
826 void free_user_context(user_ctx* ctx)
833 //env variable ends by NULL element
843 int set_environement(user_ctx *ctx)
850 if (setgid(ctx->gid)) {
851 ERR("setgid failed: %d", errno);
854 if (setuid(ctx->uid)) {
855 ERR("setuid failed: %d", errno);
859 //env variable ends by NULL element
861 if (putenv(env[i]) != 0)
868 user_ctx* get_user_context(uid_t uid)
870 /* we can use getpwnam because this is used only after a
871 * fork and just before an execv
872 * No concurrencial call can corrupt the data
873 * returned by getpwuid
875 user_ctx *context_res;
886 context_res = (user_ctx *)malloc(sizeof(user_ctx));
891 env = (char**)malloc(3* sizeof(char *));
896 // Build environment context
897 len = snprintf(NULL,0, "HOME=%s", pwd->pw_dir);
898 env[0] = (char*)malloc((len + 1)* sizeof(char));
903 sprintf(env[0], "HOME=%s", pwd->pw_dir);
904 len = snprintf(NULL,0, "USER=%s", pwd->pw_name);
905 env[1] = (char*)malloc((len + 1)* sizeof(char));
911 sprintf(env[1], "USER=%s", pwd->pw_name);
919 //env variable ends by NULL element
927 context_res->env = env;
928 context_res->uid = uid;
929 context_res->gid = pwd->pw_gid;
934 static char **__generate_argv(const char *args)
936 /* Create args vector
937 * req_id + pkgid + args
939 * vector size = # of args +
940 *(req_id + pkgid + NULL termination = 3)
941 * Last value must be NULL for execv.
947 ret_parse = g_shell_parse_argv(args,
948 &argcp, &argvp, &gerr);
949 if (FALSE == ret_parse) {
950 DBG("Failed to split args: %s", args);
951 DBG("messsage: %s", gerr->message);
955 /* Setup argument !!! */
956 /*char **args_vector =
957 calloc(argcp + 4, sizeof(char *)); */
958 char **args_vector = calloc(argcp + 1, sizeof(char *));
959 if (args_vector == NULL) {
960 ERR("Out of memory");
963 /*args_vector[0] = strdup(backend_cmd);
964 args_vector[1] = strdup(item->req_id);
965 args_vector[2] = strdup(item->pkgid); */
967 for (arg_idx = 0; arg_idx < argcp; arg_idx++) {
968 /* args_vector[arg_idx+3] = argvp[arg_idx]; */
969 args_vector[arg_idx] = argvp[arg_idx];
973 /*for(arg_idx = 0; arg_idx < argcp+3; arg_idx++) { */
974 for (arg_idx = 0; arg_idx < argcp + 1; arg_idx++) {
975 DBG(">>>>>> args_vector[%d]=%s",
976 arg_idx, args_vector[arg_idx]);
982 static void __exec_with_arg_vector(const char *cmd, char **argv, uid_t uid)
984 user_ctx* user_context = get_user_context(uid);
986 DBG("Failed to getenv for the user : %d", uid);
989 if(set_environement(user_context)){
990 DBG("Failed to set env for the user : %d", uid);
993 free_user_context(user_context);
995 /* Execute backend !!! */
996 int ret = execv(cmd, argv);
998 /* Code below: exec failure. Should not be happened! */
999 DBG(">>>>>> OOPS 2!!!");
1001 /* g_strfreev(args_vector); *//* FIXME: causes error */
1004 perror("fail to exec");
1009 gboolean queue_job(void *data)
1011 pm_dbus_msg *item = NULL;
1015 char *backend_cmd = NULL;
1017 /* Pop a job from queue */
1018 for (x = 0, ptr = begin; x < num_of_backends; x++, ptr++) {
1019 if (__is_backend_busy(x))
1022 item = _pm_queue_pop(x);
1023 if (item && item->req_type != -1)
1028 /* all backend messages queue are empty or busy */
1029 if (x == num_of_backends)
1032 __set_backend_busy(x);
1033 __set_recovery_mode(item->uid, item->pkgid, item->pkg_type);
1036 _save_queue_status(item, "processing");
1037 DBG("saved queue status. Now try fork()");
1038 /*save pkg type and pkg name for future*/
1039 strncpy(ptr->pkgtype, item->pkg_type, MAX_PKG_TYPE_LEN-1);
1040 strncpy(ptr->pkgid, item->pkgid, MAX_PKG_NAME_LEN-1);
1041 strncpy(ptr->args, item->args, MAX_PKG_ARGS_LEN-1);
1042 ptr->uid = item->uid;
1044 DBG("child forked [%d] for request type [%d]", ptr->pid, item->req_type);
1048 switch (item->req_type) {
1049 case COMM_REQ_TO_INSTALLER:
1050 DBG("before run _get_backend_cmd()");
1051 /*Check for efl-tpk app*/
1052 backend_cmd = _get_backend_cmd(item->pkg_type);
1053 if (backend_cmd == NULL)
1056 DBG("Try to exec [%s][%s]", item->pkg_type, backend_cmd);
1057 fprintf(stdout, "Try to exec [%s][%s]\n", item->pkg_type, backend_cmd);
1059 char **args_vector = __generate_argv(item->args);
1060 args_vector[0] = backend_cmd;
1062 /* Execute backend !!! */
1063 __exec_with_arg_vector(backend_cmd, args_vector, item->uid);
1066 case COMM_REQ_TO_ACTIVATOR:
1067 DBG("activator start");
1069 if (item->args[0] == '1') /* activate */
1071 else if (item->args[0] == '0') /* deactivate */
1074 DBG("error in args parameter:[%c]\n",
1079 DBG("activated val %d", val);
1084 GError *gerr = NULL;
1086 user_ctx* user_context = get_user_context(item->uid);
1088 DBG("Failed to getenv for the user : %d", item->uid);
1091 if(set_environement(user_context)){
1092 DBG("Failed to set env for the user : %d", item->uid);
1095 free_user_context(user_context);
1097 ret_parse = g_shell_parse_argv(item->args,
1098 &argcp, &argvp, &gerr);
1099 if (FALSE == ret_parse) {
1100 DBG("Failed to split args: %s", item->args);
1101 DBG("messsage: %s", gerr->message);
1105 if (!strcmp(argvp[1], "APP")) { /* in case of application */
1106 DBG("(De)activate APP");
1108 while ((opt = getopt(argcp, argvp, "l:")) != -1) {
1111 label = strdup(optarg);
1112 DBG("activated label %s", label);
1115 ERR("Incorrect argument %s\n", item->args);
1120 ret = pkgmgrinfo_appinfo_set_usr_state_enabled(item->pkgid, val, item->uid);
1121 if (ret != PMINFO_R_OK) {
1122 perror("fail to activate/deactivte package");
1127 ret = pkgmgrinfo_appinfo_set_usr_default_label(item->pkgid, label, item->uid);
1128 if (ret != PMINFO_R_OK) {
1129 perror("fail to activate/deactivte package");
1134 } else { /* in case of package */
1135 ERR("(De)activate PKG[pkgid=%s, val=%d]", item->pkgid, val);
1136 char *manifest = NULL;
1137 manifest = pkgmgr_parser_get_manifest_file(item->pkgid);
1138 if (manifest == NULL) {
1139 ERR("Failed to fetch package manifest file\n");
1142 ERR("manifest : %s\n", manifest);
1145 pkgmgrinfo_pkginfo_h handle;
1146 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(item->pkgid, item->uid, &handle);
1148 ret = pkgmgr_parser_parse_usr_manifest_for_installation(manifest,item->uid, NULL);
1150 ERR("insert in db failed\n");
1153 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
1156 ret = pkgmgrinfo_appinfo_set_usr_state_enabled(item->pkgid, val, item->uid);
1157 if (ret != PMINFO_R_OK) {
1158 perror("fail to activate/deactivte package");
1163 ret = pkgmgr_parser_parse_usr_manifest_for_uninstallation(manifest, item->uid, NULL);
1166 ERR("insert in db failed\n");
1171 case COMM_REQ_TO_MOVER:
1172 case COMM_REQ_TO_CLEARER:
1173 DBG("cleaner start");
1174 DBG("before run _get_backend_cmd()");
1175 backend_cmd = _get_backend_cmd(item->pkg_type);
1176 if (NULL == backend_cmd)
1179 DBG("Try to exec [%s][%s]", item->pkg_type, backend_cmd);
1180 fprintf(stdout, "Try to exec [%s][%s]\n", item->pkg_type, backend_cmd);
1182 char **args_vectors = __generate_argv(item->args);
1183 args_vectors[0] = backend_cmd;
1185 /* Execute backend !!! */
1186 __exec_with_arg_vector(backend_cmd, args_vectors, item->uid);
1189 case COMM_REQ_GET_SIZE:
1190 DBG("before run _get_backend_cmd()");
1191 __exec_with_arg_vector("/usr/bin/pkg_getsize", __generate_argv(item->args), item->uid);
1193 case COMM_REQ_KILL_APP:
1194 case COMM_REQ_CHECK_APP:
1195 DBG("COMM_REQ_CHECK_APP start");
1196 pkgmgrinfo_pkginfo_h handle;
1197 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(item->pkgid, item->uid, &handle);
1199 DBG("Failed to get handle\n");
1203 if (item->req_type == COMM_REQ_KILL_APP) {
1204 ret = pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP, __pkgcmd_app_cb, "kill", item->uid);
1206 DBG("pkgmgrinfo_appinfo_get_list() failed\n");
1207 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
1210 } else if (item->req_type == COMM_REQ_CHECK_APP) {
1211 ret = pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP, __pkgcmd_app_cb, "check", item->uid);
1213 DBG("pkgmgrinfo_appinfo_get_list() failed\n");
1214 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
1218 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
1220 case COMM_REQ_CLEAR_CACHE_DIR:
1221 __exec_with_arg_vector("/usr/bin/pkg_clearcache", __generate_argv(item->args), item->uid);
1225 _save_queue_status(item, "done");
1230 fprintf(stderr, "Fail to execute_fork()\n");
1233 default: /* parent */
1234 DBG("parent exit\n");
1235 _save_queue_status(item, "done");
1244 #define IS_WHITESPACE(CHAR) \
1245 ((CHAR == ' ' || CHAR == '\t' || CHAR == '\r' || CHAR == '\n') ? TRUE : FALSE)
1247 void _app_str_trim(char *input)
1249 char *trim_str = input;
1254 while (*input != 0) {
1255 if (!IS_WHITESPACE(*input)) {
1266 char *_get_backend_cmd(char *type)
1269 char buffer[1024] = { 0 };
1270 char *command = NULL;
1272 fp = fopen(PKG_CONF_PATH, "r");
1278 while (fgets(buffer, 1024, fp) != NULL) {
1279 if (buffer[0] == '#')
1282 _app_str_trim(buffer);
1284 if ((path = strstr(buffer, PKG_BACKEND)) != NULL) {
1285 DBG("buffer [%s]", buffer);
1286 path = path + strlen(PKG_BACKEND);
1287 DBG("path [%s]", path);
1290 (char *)malloc(sizeof(char) * strlen(path) +
1292 if (command == NULL) {
1297 size = strlen(path) + strlen(type) + 1;
1298 snprintf(command, size, "%s%s", path, type);
1299 command[strlen(path) + strlen(type)] = '\0';
1300 DBG("command [%s]", command);
1308 memset(buffer, 0x00, 1024);
1314 return NULL; /* cannot find proper command */
1317 static int __get_caller_info(GDBusConnection *connection,
1318 GDBusMethodInvocation *invocation,
1319 char **client, char **user, char **session)
1321 const gchar *sender = NULL;
1325 char buf[BUFMAX] = {0, };
1328 sender = g_dbus_method_invocation_get_sender(invocation);
1329 if (sender == NULL) {
1330 ERR("get sender failed");
1331 ret = COMM_RET_ERROR;
1335 r = cynara_creds_gdbus_get_client(connection, sender,
1336 CLIENT_METHOD_DEFAULT, client);
1337 if (r != CYNARA_API_SUCCESS) {
1338 cynara_strerror(r, buf, BUFMAX);
1339 ERR("cynara_creds_dbus_get_client failed: %s", buf);
1340 ret = COMM_RET_ERROR;
1344 r = cynara_creds_gdbus_get_user(connection, sender,
1345 USER_METHOD_DEFAULT, user);
1346 if (r != CYNARA_API_SUCCESS) {
1347 cynara_strerror(r, buf, BUFMAX);
1348 ERR("cynara_creds_dbus_get_user failed: %s", buf);
1349 ret = COMM_RET_ERROR;
1353 r = cynara_creds_gdbus_get_pid(connection, sender, &pid);
1354 if (r != CYNARA_API_SUCCESS) {
1355 cynara_strerror(r, buf, BUFMAX);
1356 ERR("cynara_creds_dbus_get_pid failed: %s", buf);
1357 ret = COMM_RET_ERROR;
1361 *session = cynara_session_from_pid(pid);
1362 if (*session == NULL) {
1363 ERR("cynara_session_from_pid failed");
1364 ret = COMM_RET_ERROR;
1367 DBG("session: %s", session);
1373 static void __handle_method_call(GDBusConnection *connection,
1374 const gchar *sender, const gchar *object_path,
1375 const gchar *interface_name, const gchar *method_name,
1376 GVariant *parameters, GDBusMethodInvocation *invocation,
1379 gchar *req_id = NULL;
1381 gchar *pkg_type = NULL;
1382 gchar *pkgid = NULL;
1390 if (g_strcmp0(method_name, "Request") != 0) {
1391 ERR("unknown method call");
1395 if (__get_caller_info(connection, invocation, &client, &user,
1397 g_dbus_method_invocation_return_value(invocation,
1398 g_variant_new("(i)", ret));
1402 g_variant_get(parameters, "(&si&s&s&si)", &req_id, &req_type, &pkg_type,
1403 &pkgid, &args, &uid);
1404 if (req_id == NULL || req_type == -1 || pkg_type == NULL ||
1405 pkgid == NULL || args == NULL || uid == -1) {
1406 ERR("failed to get parameters");
1413 req_cb(NULL, uid, req_id, req_type, pkg_type, pkgid, args,
1414 client, session, user, &ret);
1416 g_dbus_method_invocation_return_value(invocation,
1417 g_variant_new("(i)", ret));
1424 static const char instropection_xml[] =
1426 " <interface name='org.tizen.pkgmgr'>"
1427 " <method name='Request'>"
1428 " <arg type='s' name='req_id' direction='in'/>"
1429 " <arg type='i' name='req_type' direction='in'/>"
1430 " <arg type='s' name='pkg_type' direction='in'/>"
1431 " <arg type='s' name='pkg_id' direction='in'/>"
1432 " <arg type='s' name='args' direction='in'/>"
1433 " <arg type='i' name='uid' direction='in'/>"
1434 " <arg type='i' name='ret' direction='out'/>"
1438 static const GDBusInterfaceVTable interface_vtable =
1440 __handle_method_call,
1444 static GDBusNodeInfo *instropection_data;
1445 static guint reg_id;
1446 static guint owner_id;
1448 static void __on_bus_acquired(GDBusConnection *connection, const gchar *name,
1452 DBG("on bus acquired");
1454 reg_id = g_dbus_connection_register_object(connection,
1455 COMM_PKGMGR_DBUS_OBJECT_PATH,
1456 instropection_data->interfaces[0],
1457 &interface_vtable, NULL, NULL, NULL);
1460 ERR("failed to register object");
1463 static void __on_name_acquired(GDBusConnection *connection, const gchar *name,
1466 DBG("on name acquired: %s", name);
1469 static void __on_name_lost(GDBusConnection *connection, const gchar *name,
1472 DBG("on name lost: %s", name);
1475 static int __init_dbus(void)
1477 instropection_data = g_dbus_node_info_new_for_xml(instropection_xml, NULL);
1479 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, COMM_PKGMGR_DBUS_SERVICE,
1480 G_BUS_NAME_OWNER_FLAGS_NONE, __on_bus_acquired,
1481 __on_name_acquired, __on_name_lost, NULL, NULL);
1486 static void __fini_dbus(void)
1488 g_bus_unown_name(owner_id);
1489 g_dbus_node_info_unref(instropection_data);
1492 int main(int argc, char *argv[])
1494 FILE *fp_status = NULL;
1495 char buf[32] = { 0, };
1497 char *backend_cmd = NULL;
1498 char *backend_name = NULL;
1501 DBG("server start");
1503 if (argv[1] && (strcmp(argv[1], "init") == 0)) {
1504 /* if current status is "processing",
1505 execute related backend with '-r' option */
1506 if (!(fp_status = fopen(STATUS_FILE, "r")))
1507 return 0; /*if file is not exist, terminated. */
1508 /* if processing <-- unintended termination */
1509 if (fgets(buf, 32, fp_status) &&
1510 strcmp(buf, "processing") == 0) {
1512 if (pid == 0) { /* child */
1513 if (fgets(buf, 32, fp_status))
1514 backend_cmd = _get_backend_cmd(buf);
1515 if (!backend_cmd) { /* if NULL, */
1517 " backend command");
1521 strrchr(backend_cmd, '/');
1523 execl(backend_cmd, backend_name, "-r",
1527 fprintf(fp_status, " ");
1531 } else if (pid < 0) { /* error */
1535 } else { /* parent */
1537 DBG("parent end\n");
1538 fprintf(fp_status, " ");
1545 r = _pm_queue_init();
1547 DBG("Queue Initialization Failed\n");
1551 r = __init_backend_info();
1553 DBG("backend info init failed");
1557 r = cynara_initialize(&p_cynara, NULL);
1558 if (r != CYNARA_API_SUCCESS) {
1559 ERR("cynara initialize failed with code=%d", r);
1565 ERR("dbus init failed");
1569 #if !GLIB_CHECK_VERSION(2,35,0)
1572 mainloop = g_main_loop_new(NULL, FALSE);
1574 ERR("g_main_loop_new failed");
1578 DBG("Main loop is created.");
1580 g_main_loop_run(mainloop);
1582 DBG("Quit main loop.");
1584 cynara_finish(p_cynara);
1585 __fini_backend_info();
1588 DBG("package manager server terminated.");