Implement app signal related with app disable/enable
[platform/core/appfw/pkgmgr-server.git] / src / pkgmgr-server.c
1 /*
2  * slp-pkgmgr
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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>
8  *
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
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
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.
20  *
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <unistd.h>
28 #include <pwd.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <sys/stat.h>
32 #include <dirent.h>
33 #include <sys/types.h>
34 #include <fcntl.h>
35 #include <signal.h>
36
37 #include <glib.h>
38 #include <gio/gio.h>
39
40 #include <pkgmgr-info.h>
41 #include <pkgmgr/pkgmgr_parser.h>
42 #include <tzplatform_config.h>
43 #include <drm-tizen-apps.h>
44
45 #include "pkgmgr_installer.h"
46 #include "pkgmgr-server.h"
47 #include "pm-queue.h"
48 #include "comm_config.h"
49 #include "package-manager.h"
50
51 #define BUFMAX 128
52 #define NO_MATCHING_FILE 11
53
54 #define OWNER_ROOT 0
55 #define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)
56
57 typedef struct  {
58         char **env;
59         uid_t uid;
60         gid_t gid;
61 } user_ctx;
62
63
64 /*
65 8 bit value to represent maximum 8 backends.
66 Each bit position corresponds to a queue slot which
67 is dynamically determined.
68 */
69 char backend_busy = 0;
70 extern int num_of_backends;
71
72 struct signal_info_t {
73         pid_t pid;
74         int status;
75 };
76
77 static int pipe_sig[2];
78 static GIOChannel *pipe_io;
79 static guint pipe_wid;
80
81 backend_info *begin;
82 extern queue_info_map *start;
83 extern int entries;
84
85 GMainLoop *mainloop = NULL;
86
87
88 /* operation_type */
89 typedef enum {
90         OPERATION_INSTALL = 0,
91         OPERATION_UNINSTALL,
92         OPERATION_ACTIVATE,
93         OPERATION_REINSTALL,
94         OPERATION_MAX
95 } OPERATION_TYPE;
96
97 static int __check_backend_status_for_exit(void);
98 static int __check_queue_status_for_exit(void);
99 static int __is_backend_busy(int position);
100 static void __set_backend_busy(int position);
101 static void __set_backend_free(int position);
102 static void sighandler(int signo);
103
104 gboolean exit_server(void *data);
105
106 /* To check whether a particular backend is free/busy*/
107 static int __is_backend_busy(int position)
108 {
109         return backend_busy & 1<<position;
110 }
111 /*To set a particular backend as busy*/
112 static void __set_backend_busy(int position)
113 {
114         backend_busy = backend_busy | 1<<position;
115 }
116 /*To set a particular backend as free */
117 static void __set_backend_free(int position)
118 {
119         backend_busy = backend_busy & ~(1<<position);
120 }
121
122 static int __is_global(uid_t uid)
123 {
124         return (uid == OWNER_ROOT || uid == GLOBAL_USER) ? 1 : 0;
125 }
126
127 static const char *__get_recovery_file_path(uid_t uid)
128 {
129         const char *path;
130
131         if (!__is_global(uid))
132                 tzplatform_set_user(uid);
133
134         path = tzplatform_getenv(__is_global(uid)
135                         ? TZ_SYS_RW_PACKAGES : TZ_USER_PACKAGES);
136
137         tzplatform_reset_user();
138
139         return path;
140 }
141
142 static void __set_recovery_mode(uid_t uid, char *pkgid, char *pkg_type)
143 {
144         char recovery_file[MAX_PKG_NAME_LEN] = { 0, };
145         char buffer[MAX_PKG_NAME_LEN] = { 0 };
146         char *pkgid_tmp = NULL;
147         FILE *rev_file = NULL;
148
149         if (pkgid == NULL) {
150                 DBG("pkgid is null\n");
151                 return;
152         }
153
154         /*if pkgid has a "/"charactor, that is a path name for installation, then extract pkgid from absolute path*/
155         if (strstr(pkgid, "/")) {
156                 pkgid_tmp = strrchr(pkgid, '/') + 1;
157                 if (pkgid_tmp == NULL) {
158                         DBG("pkgid_tmp[%s] is null\n", pkgid);
159                         return;
160                 }
161                 snprintf(recovery_file, sizeof(recovery_file), "%s/%s", __get_recovery_file_path(uid), pkgid_tmp);
162         } else {
163                 snprintf(recovery_file, sizeof(recovery_file), "%s/%s", __get_recovery_file_path(uid), pkgid);
164         }
165
166         rev_file = fopen(recovery_file, "w");
167         if (rev_file== NULL) {
168                 DBG("rev_file[%s] is null\n", recovery_file);
169                 return;
170         }
171
172         snprintf(buffer, MAX_PKG_NAME_LEN, "pkgid : %s\n", pkgid);
173         fwrite(buffer, sizeof(char), strlen(buffer), rev_file);
174
175         fclose(rev_file);
176 }
177
178 static void __unset_recovery_mode(uid_t uid, char *pkgid, char *pkg_type)
179 {
180         int ret = -1;
181         char recovery_file[MAX_PKG_NAME_LEN] = { 0, };
182         char *pkgid_tmp = NULL;
183
184         if (pkgid == NULL) {
185                 DBG("pkgid is null\n");
186                 return;
187         }
188
189         /*if pkgid has a "/"charactor, that is a path name for installation, then extract pkgid from absolute path*/
190         if (strstr(pkgid, "/")) {
191                 pkgid_tmp = strrchr(pkgid, '/') + 1;
192                 if (pkgid_tmp == NULL) {
193                         DBG("pkgid_tmp[%s] is null\n", pkgid);
194                         return;
195                 }
196                 snprintf(recovery_file, sizeof(recovery_file), "%s/%s", __get_recovery_file_path(uid), pkgid_tmp);
197         } else {
198                 snprintf(recovery_file, sizeof(recovery_file), "%s/%s", __get_recovery_file_path(uid), pkgid);
199         }
200
201         ret = remove(recovery_file);
202         if (ret < 0)
203                 DBG("remove recovery_file[%s] fail\n", recovery_file);
204 }
205
206 static void __send_app_signal(uid_t uid, const char *req_id,
207                 const char *pkg_type, const char *pkgid, const char *appid,
208                 const char *key, const char *val)
209 {
210         pkgmgr_installer *pi;
211
212         pi = pkgmgr_installer_new();
213         if (!pi) {
214                 DBG("Failure in creating the pkgmgr_installer object");
215                 return;
216         }
217
218         if (pkgmgr_installer_set_request_type(pi,PKGMGR_REQ_ENABLE_DISABLE_APP))
219                 goto catch;
220         if (pkgmgr_installer_set_session_id(pi, req_id))
221                 goto catch;
222         pkgmgr_installer_send_app_signal(pi, pkg_type, pkgid, appid, key, val);
223
224 catch:
225         pkgmgr_installer_free(pi);
226
227         return;
228 }
229
230 static void send_fail_signal(char *pname, char *ptype, char *args)
231 {
232         DBG("send_fail_signal start\n");
233         gboolean ret_parse;
234         gint argcp;
235         gchar **argvp;
236         GError *gerr = NULL;
237         pkgmgr_installer *pi;
238         pi = pkgmgr_installer_new();
239         if (!pi) {
240                 DBG("Failure in creating the pkgmgr_installer object");
241                 return;
242         }
243         ret_parse = g_shell_parse_argv(args,
244                                        &argcp, &argvp, &gerr);
245         if (FALSE == ret_parse) {
246                 DBG("Failed to split args: %s", args);
247                 DBG("messsage: %s", gerr->message);
248                 pkgmgr_installer_free(pi);
249                 return;
250         }
251
252         pkgmgr_installer_receive_request(pi, argcp, argvp);
253         pkgmgr_installer_send_signal(pi, ptype, pname, "end", "fail");
254         pkgmgr_installer_free(pi);
255         return;
256 }
257
258 static gboolean pipe_io_handler(GIOChannel *io, GIOCondition cond, gpointer data)
259 {
260         int x;
261         GError *err = NULL;
262         GIOStatus s;
263         gsize len;
264         struct signal_info_t info;
265         backend_info *ptr = begin;
266
267         s = g_io_channel_read_chars(io, (gchar *)&info, sizeof(struct signal_info_t), &len, &err);
268         if (s != G_IO_STATUS_NORMAL) {
269                 ERR("Signal pipe read failed: %s", err->message);
270                 g_error_free(err);
271                 return TRUE;
272         }
273
274         for (x = 0; x < num_of_backends; x++, ptr++) {
275                 if (ptr && ptr->pid == info.pid)
276                         break;
277         }
278
279         if (x == num_of_backends) {
280                 ERR("Unknown child exit");
281                 return -1;
282         }
283
284         __set_backend_free(x);
285         __unset_recovery_mode(ptr->uid, ptr->pkgid, ptr->pkgtype);
286         if (WIFSIGNALED(info.status) || WEXITSTATUS(info.status)) {
287                 send_fail_signal(ptr->pkgid, ptr->pkgtype, ptr->args);
288                 DBG("backend[%s] exit with error", ptr->pkgtype);
289         } else {
290                 DBG("backend[%s] exit", ptr->pkgtype);
291         }
292
293         g_idle_add(queue_job, NULL);
294
295         return TRUE;
296 }
297
298 static int __init_backend_info(void)
299 {
300         backend_info *ptr;
301
302         /*Allocate memory for holding pid, pkgtype and pkgid*/
303         ptr = (backend_info*)calloc(num_of_backends, sizeof(backend_info));
304         if (ptr == NULL) {
305                 DBG("Malloc Failed\n");
306                 return -1;
307         }
308         begin = ptr;
309
310         if (pipe(pipe_sig)) {
311                 ERR("create pipe failed");
312                 return -1;
313         }
314
315         pipe_io = g_io_channel_unix_new(pipe_sig[0]);
316         g_io_channel_set_encoding(pipe_io, NULL, NULL);
317         g_io_channel_set_buffered(pipe_io, FALSE);
318         pipe_wid = g_io_add_watch(pipe_io, G_IO_IN, pipe_io_handler, NULL);
319
320         return 0;
321 }
322
323 static void __fini_backend_info(void)
324 {
325         g_source_remove(pipe_wid);
326         g_io_channel_unref(pipe_io);
327         close(pipe_sig[0]);
328         close(pipe_sig[1]);
329
330         /*Free backend info */
331         free(begin);
332 }
333
334 static void sighandler(int signo)
335 {
336         struct signal_info_t info;
337
338         info.pid = waitpid(-1, &info.status, WNOHANG);
339         if (write(pipe_sig[1], &info, sizeof(struct signal_info_t)) < 0)
340                 ERR("failed to write result: %s", strerror(errno));
341 }
342
343 static int __register_signal_handler(void)
344 {
345         static int sig_reg = 0;
346         struct sigaction act;
347
348         if (sig_reg)
349                 return 0;
350
351         act.sa_handler = sighandler;
352         sigemptyset(&act.sa_mask);
353         act.sa_flags = SA_NOCLDSTOP;
354         if (sigaction(SIGCHLD, &act, NULL) < 0) {
355                 ERR("signal: SIGCHLD failed\n");
356                 return -1;
357         }
358
359         g_timeout_add_seconds(2, exit_server, NULL);
360
361         sig_reg = 1;
362         return 0;
363 }
364
365 static int __check_backend_status_for_exit(void)
366 {
367         int i = 0;
368         for(i = 0; i < num_of_backends; i++)
369         {
370                 if (!__is_backend_busy(i))
371                         continue;
372                 else
373                         return 0;
374         }
375         return 1;
376 }
377
378 static int __check_queue_status_for_exit(void)
379 {
380         pm_queue_data *head[MAX_QUEUE_NUM] = {NULL,};
381         queue_info_map *ptr = NULL;
382         ptr = start;
383         int i = 0;
384         int c = 0;
385         int slot = -1;
386         for(i = 0; i < entries; i++)
387         {
388                 if (ptr->queue_slot <= slot) {
389                         ptr++;
390                         continue;
391                 }
392                 else {
393                         head[c] = ptr->head;
394                         slot = ptr->queue_slot;
395                         c++;
396                         ptr++;
397                 }
398         }
399         for(i = 0; i < num_of_backends; i++)
400         {
401                 if (!head[i])
402                         continue;
403                 else
404                         return 0;
405         }
406         return 1;
407 }
408
409 gboolean exit_server(void *data)
410 {
411         DBG("exit_server Start\n");
412         if (__check_backend_status_for_exit() &&
413                         __check_queue_status_for_exit()) {
414                 if (!getenv("PMS_STANDALONE")) {
415                         g_main_loop_quit(mainloop);
416                         return FALSE;
417                 }
418         }
419         return TRUE;
420 }
421
422 static int __pkgcmd_read_proc(const char *path, char *buf, int size)
423 {
424         int fd;
425         int ret;
426         if (buf == NULL || path == NULL)
427                 return -1;
428         fd = open(path, O_RDONLY);
429         if (fd < 0)
430                 return -1;
431         ret = read(fd, buf, size - 1);
432         if (ret <= 0) {
433                 close(fd);
434                 return -1;
435         } else
436                 buf[ret] = 0;
437         close(fd);
438         return ret;
439 }
440
441 static int __pkgcmd_find_pid_by_cmdline(const char *dname,
442                         const char *cmdline, const char *apppath)
443 {
444         int pid = 0;
445
446         if (strcmp(cmdline, apppath) == 0) {
447                 pid = atoi(dname);
448                 if (pid != getpgid(pid))
449                         pid = 0;
450         }
451         return pid;
452 }
453
454 static int __pkgcmd_proc_iter_kill_cmdline(const char *apppath, int option)
455 {
456         DIR *dp;
457         struct dirent *dentry;
458         int pid;
459         int ret;
460         char buf[1024] = {'\0'};
461         int pgid;
462
463         dp = opendir("/proc");
464         if (dp == NULL) {
465                 return -1;
466         }
467
468         while ((dentry = readdir(dp)) != NULL) {
469                 if (!isdigit(dentry->d_name[0]))
470                         continue;
471
472                 snprintf(buf, sizeof(buf), "/proc/%s/cmdline", dentry->d_name);
473                 ret = __pkgcmd_read_proc(buf, buf, sizeof(buf));
474                 if (ret <= 0)
475                         continue;
476
477                 pid = __pkgcmd_find_pid_by_cmdline(dentry->d_name, buf, apppath);
478                 if (pid > 0) {
479                         if (option == 0) {
480                                 closedir(dp);
481                                 return pid;
482                         }
483                         pgid = getpgid(pid);
484                         if (pgid <= 1) {
485                                 closedir(dp);
486                                 return -1;
487                         }
488                         if (killpg(pgid, SIGKILL) < 0) {
489                                 closedir(dp);
490                                 return -1;
491                         }
492                         closedir(dp);
493                         return pid;
494                 }
495         }
496         closedir(dp);
497         return 0;
498 }
499
500 static void __make_pid_info_file(char *req_key, int pid)
501 {
502         FILE* file;
503         int fd;
504         char buf[MAX_PKG_TYPE_LEN] = {0};
505         char info_file[PATH_MAX] = {'\0'};
506
507         if(req_key == NULL)
508                 return;
509
510         snprintf(info_file, PATH_MAX, "/tmp/pkgmgr/%s", req_key);
511
512         DBG("info_path(%s)", info_file);
513         file = fopen(info_file, "w");
514         if (file == NULL) {
515                 ERR("Couldn't open the file(%s)", info_file);
516                 return;
517         }
518
519         snprintf(buf, MAX_PKG_TYPE_LEN, "%d\n", pid);
520         fwrite(buf, 1, strlen(buf), file);
521
522         fflush(file);
523         fd = fileno(file);
524         fsync(fd);
525         fclose(file);
526 }
527
528 static int __pkgcmd_app_cb(const pkgmgrinfo_appinfo_h handle, void *user_data)
529 {
530         char *pkgid;
531         char *exec;
532         int ret;
533         int pid = -1;
534
535         if (handle == NULL) {
536                 perror("appinfo handle is NULL\n");
537                 exit(1);
538         }
539         ret = pkgmgrinfo_appinfo_get_exec(handle, &exec);
540         if (ret) {
541                 perror("Failed to get app exec path\n");
542                 exit(1);
543         }
544         ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgid);
545         if (ret) {
546                 perror("Failed to get pkgid\n");
547                 exit(1);
548         }
549
550         if (strcmp(user_data, "kill") == 0)
551                 pid = __pkgcmd_proc_iter_kill_cmdline(exec, 1);
552         else if(strcmp(user_data, "check") == 0)
553                 pid = __pkgcmd_proc_iter_kill_cmdline(exec, 0);
554
555         __make_pid_info_file(pkgid, pid);
556
557         return 0;
558 }
559
560 void free_user_context(user_ctx* ctx)
561 {
562         char **env = NULL;
563         int i = 0;
564         if (!ctx)
565                 return;
566         env = ctx->env;
567         //env variable ends by NULL element
568         while (env[i]) {
569                 free(env[i]);
570                 i++;
571         }
572         free(env);
573         env = NULL;
574         free(ctx);
575 }
576
577 int set_environement(user_ctx *ctx)
578 {
579         int i = 0;
580         int res = 0;
581         char **env = NULL;
582         if (!ctx)
583                 return -1;;
584         if (setgid(ctx->gid)) {
585                 ERR("setgid failed: %d", errno);
586                 return -1;
587         }
588         if (setuid(ctx->uid)) {
589                 ERR("setuid failed: %d", errno);
590                 return -1;
591         }
592         env = ctx->env;
593         //env variable ends by NULL element
594         while (env[i]) {
595                 if (putenv(env[i]) != 0)
596                         res = -1;
597                 i++;
598         }
599         return res;
600 }
601
602 user_ctx* get_user_context(uid_t uid)
603 {
604         /* we can use getpwnam because this is used only after a
605          * fork and just before an execv
606          * No concurrencial call can corrupt the data
607          * returned by getpwuid
608          */
609         user_ctx *context_res;
610         char **env = NULL;
611         struct passwd * pwd;
612         int len;
613         int ret = 0;
614
615         pwd = getpwuid(uid);
616         if (!pwd)
617                 return NULL;
618
619         do {
620                 context_res = (user_ctx *)malloc(sizeof(user_ctx));
621                 if (!context_res) {
622                         ret = -1;
623                         break;
624                 }
625                 env = (char**)malloc(3* sizeof(char *));
626                 if (!env) {
627                         ret = -1;
628                         break;
629                 }
630                 // Build environment context
631                 len = snprintf(NULL,0, "HOME=%s", pwd->pw_dir);
632                 env[0] = (char*)malloc((len + 1)* sizeof(char));
633                 if(env[0] == NULL) {
634                         ret = -1;
635                         break;
636                 }
637                 sprintf(env[0], "HOME=%s", pwd->pw_dir);
638                 len = snprintf(NULL,0, "USER=%s", pwd->pw_name);
639                 env[1] = (char*)malloc((len + 1)* sizeof(char));
640                 if(env[1] == NULL) {
641                         ret = -1;
642                         break;
643                 }
644
645                 sprintf(env[1], "USER=%s", pwd->pw_name);
646                 env[2] = NULL;
647         } while (0);
648
649         if (ret == -1) {
650                 free(context_res);
651                 context_res = NULL;
652                 int i = 0;
653                 //env variable ends by NULL element
654                 while (env && env[i]) {
655                         free(env[i]);
656                         i++;
657                 }
658                 free(env);
659                 env = NULL;
660         } else {
661                 context_res->env = env;
662                 context_res->uid = uid;
663                 context_res->gid = pwd->pw_gid;
664         }
665         return context_res;
666 }
667
668 static char **__generate_argv(const char *args)
669 {
670         /* Create args vector
671          * req_id + pkgid + args
672          *
673          * vector size = # of args +
674          *(req_id + pkgid + NULL termination = 3)
675          * Last value must be NULL for execv.
676          */
677         gboolean ret_parse;
678         gint argcp;
679         gchar **argvp;
680         GError *gerr = NULL;
681         int i;
682
683         ret_parse = g_shell_parse_argv(args,
684                         &argcp, &argvp, &gerr);
685         if (FALSE == ret_parse) {
686                 DBG("Failed to split args: %s", args);
687                 DBG("messsage: %s", gerr->message);
688                 exit(1);
689         }
690
691         /* dbg */
692         for (i = 0; i < argcp; i++)
693                 DBG(">>>>>> argsv[%d]=%s", i, argvp[i]);
694
695         return argvp;
696 }
697
698 void __set_environment(gpointer user_data)
699 {
700         user_ctx *ctx = (user_ctx *)user_data;
701
702         if (set_environement(ctx))
703                 DBG("Failed to set env for the user : %d", ctx->uid);
704 }
705
706 static int __fork_and_exec_with_args(char **argv, uid_t uid)
707 {
708         user_ctx* user_context;
709         GError *error = NULL;
710         gboolean ret;
711         int pid;
712
713         user_context = get_user_context(uid);
714         if (!user_context) {
715                 DBG("Failed to getenv for the user : %d", uid);
716                 return -1;
717         }
718
719         ret = g_spawn_async(NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
720                         __set_environment, (gpointer)user_context, &pid,
721                         &error);
722         if (ret != TRUE) {
723                 ERR("Failed to excute backend: %s", error->message);
724                 g_error_free(error);
725         }
726
727         free_user_context(user_context);
728
729         return pid;
730 }
731
732 void __change_item_info(pm_dbus_msg *item, uid_t uid)
733 {
734         int ret = 0;
735         char *pkgid = NULL;
736         pkgmgrinfo_appinfo_h handle = NULL;
737
738         ret = pkgmgrinfo_appinfo_get_usr_appinfo(item->pkgid, uid, &handle);
739         if (ret != PMINFO_R_OK)
740                 return;
741
742         ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgid);
743         if (ret != PMINFO_R_OK) {
744                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
745                 return;
746         }
747
748         strncpy(item->appid, item->pkgid, sizeof(item->pkgid) - 1);
749         memset((item->pkgid),0,MAX_PKG_NAME_LEN);
750         strncpy(item->pkgid, pkgid, sizeof(item->pkgid) - 1);
751
752         pkgmgrinfo_appinfo_destroy_appinfo(handle);
753 }
754
755 static int __process_install(pm_dbus_msg *item)
756 {
757         char *backend_cmd;
758         char **argv;
759         char args[MAX_PKG_ARGS_LEN] = {'\0', };
760         int pid;
761
762         backend_cmd = _get_backend_cmd(item->pkg_type);
763         if (backend_cmd == NULL)
764                 return -1;
765
766         snprintf(args, sizeof(args), "%s -k %s -i %s %s", backend_cmd,
767                         item->req_id, item->pkgid, item->args);
768
769         argv = __generate_argv(args);
770
771         pid = __fork_and_exec_with_args(argv, item->uid);
772         g_strfreev(argv);
773         free(backend_cmd);
774
775         return pid;
776 }
777
778 static int __process_reinstall(pm_dbus_msg *item)
779 {
780         char *backend_cmd;
781         char **argv;
782         char args[MAX_PKG_ARGS_LEN];
783         int pid;
784
785         backend_cmd = _get_backend_cmd(item->pkg_type);
786         if (backend_cmd == NULL)
787                 return -1;
788
789         snprintf(args, sizeof(args), "%s -k %s -r %s", backend_cmd,
790                         item->req_id, item->pkgid);
791         argv = __generate_argv(args);
792
793         pid = __fork_and_exec_with_args(argv, item->uid);
794
795         g_strfreev(argv);
796         free(backend_cmd);
797
798         return pid;
799 }
800
801 static int __process_uninstall(pm_dbus_msg *item)
802 {
803         char *backend_cmd;
804         char **argv;
805         char args[MAX_PKG_ARGS_LEN];
806         int pid;
807
808         backend_cmd = _get_backend_cmd(item->pkg_type);
809         if (backend_cmd == NULL)
810                 return -1;
811
812         snprintf(args, sizeof(args), "%s -k %s -d %s", backend_cmd,
813                         item->req_id, item->pkgid);
814         argv = __generate_argv(args);
815
816         pid = __fork_and_exec_with_args(argv, item->uid);
817
818         g_strfreev(argv);
819         free(backend_cmd);
820
821         return pid;
822 }
823
824 static int __process_move(pm_dbus_msg *item)
825 {
826         char *backend_cmd;
827         char **argv;
828         char args[MAX_PKG_ARGS_LEN];
829         int pid;
830
831         backend_cmd = _get_backend_cmd(item->pkg_type);
832         if (backend_cmd == NULL)
833                 return -1;
834
835         /* TODO: set movetype */
836         snprintf(args, sizeof(args), "%s -k %s -m %s -t %s", backend_cmd,
837                         item->req_id, item->pkgid, item->args);
838         argv = __generate_argv(args);
839
840         pid = __fork_and_exec_with_args(argv, item->uid);
841
842         g_strfreev(argv);
843         free(backend_cmd);
844
845         return pid;
846 }
847
848 static int __process_enable_pkg(pm_dbus_msg *item)
849 {
850         /* TODO */
851         return 0;
852 }
853
854 static int __process_disable_pkg(pm_dbus_msg *item)
855 {
856         /* TODO */
857         return 0;
858 }
859
860 static int __process_enable_app(pm_dbus_msg *item)
861 {
862         int ret = -1;
863
864         __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->pkgid, "start", "enable_app");
865
866         /* get actual pkgid and replace it to appid which is currently stored at pkgid variable */
867         __change_item_info(item, item->uid);
868         if (strlen(item->appid) == 0) {
869                 __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->pkgid, "end", "fail");
870                 return ret;
871         }
872
873         ret = pkgmgr_parser_update_app_disable_info_in_usr_db(item->appid, item->uid, 0);
874         if (ret != PMINFO_R_OK)
875                 __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->appid, "end", "fail");
876         else
877                 __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->appid, "end", "ok");
878
879         return ret;
880 }
881
882 static int __process_disable_app(pm_dbus_msg *item)
883 {
884         int ret = -1;
885
886         __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->pkgid, "start", "disable_app");
887
888         /* get actual pkgid and replace it to appid which is currently stored at pkgid variable */
889         __change_item_info(item, item->uid);
890         if (strlen(item->appid) == 0) {
891                 __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->pkgid, "end", "fail");
892                 return ret;
893         }
894
895         ret = pkgmgr_parser_update_app_disable_info_in_usr_db(item->appid, item->uid, 1);
896         if (ret != PMINFO_R_OK)
897                 __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->appid, "end", "fail");
898         else
899                 __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->appid, "end", "ok");
900
901         return ret;
902 }
903
904 static int __process_enable_global_app_for_uid(pm_dbus_msg *item)
905 {
906         int ret = -1;
907
908         __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->pkgid, "start", "enable_global_app_for_uid");
909
910         /* get actual pkgid and replace it to appid which is currently stored at pkgid variable */
911         __change_item_info(item, GLOBAL_USER);
912         if (strlen(item->appid) == 0) {
913                 __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->pkgid, "end", "fail");
914                 return ret;
915         }
916
917         ret = pkgmgr_parser_update_global_app_disable_for_uid_info_in_db(item->appid, item->uid, 0);
918         if (ret != PMINFO_R_OK)
919                 __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->appid, "end", "fail");
920         else
921                 __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->appid, "end", "ok");
922
923         return ret;
924 }
925
926 static int __process_disable_global_app_for_uid(pm_dbus_msg *item)
927 {
928         int ret = -1;
929
930         __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->pkgid, "start", "disable_global_app_for_uid");
931
932         /* get actual pkgid and replace it to appid which is currently stored at pkgid variable */
933         __change_item_info(item, GLOBAL_USER);
934         if (strlen(item->appid) == 0) {
935                 __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->pkgid, "end", "fail");
936                 return ret;
937         }
938
939         ret = pkgmgr_parser_update_global_app_disable_for_uid_info_in_db(item->appid, item->uid, 1);
940         if (ret != PMINFO_R_OK)
941                 __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->appid, "end", "fail");
942         else
943                 __send_app_signal(item->uid, item->req_id, item->pkg_type, item->pkgid, item->appid, "end", "ok");
944
945         return ret;
946 }
947
948 static int __process_getsize(pm_dbus_msg *item)
949 {
950         static const char *backend_cmd = "/usr/bin/pkg_getsize";
951         char **argv;
952         char args[MAX_PKG_ARGS_LEN];
953         int pid;
954
955         snprintf(args, sizeof(args), "%s %s %s -k %s", backend_cmd, item->pkgid,
956                         item->args, item->req_id);
957         argv = __generate_argv(args);
958         pid = __fork_and_exec_with_args(argv, item->uid);
959
960         g_strfreev(argv);
961
962         return pid;
963 }
964
965 static int __process_cleardata(pm_dbus_msg *item)
966 {
967         char *backend_cmd;
968         char **argv;
969         char args[MAX_PKG_ARGS_LEN];
970         int pid;
971
972         backend_cmd = _get_backend_cmd(item->pkg_type);
973         if (backend_cmd == NULL)
974                 return -1;
975
976         /* TODO: set movetype */
977         snprintf(args, sizeof(args), "%s -k %s -c %s", backend_cmd,
978                         item->req_id, item->pkgid);
979         argv = __generate_argv(args);
980
981         pid = __fork_and_exec_with_args(argv, item->uid);
982
983         g_strfreev(argv);
984         free(backend_cmd);
985
986         return pid;
987 }
988
989 static int __process_clearcache(pm_dbus_msg *item)
990 {
991         static const char *backend_cmd = "/usr/bin/pkg_clearcache";
992         char **argv;
993         char args[MAX_PKG_ARGS_LEN];
994         int pid;
995
996         snprintf(args, sizeof(args), "%s %s", backend_cmd, item->pkgid);
997         argv = __generate_argv(args);
998         pid = __fork_and_exec_with_args(argv, item->uid);
999
1000         g_strfreev(argv);
1001
1002         return pid;
1003 }
1004
1005 static int __process_kill(pm_dbus_msg *item)
1006 {
1007         int ret;
1008         pkgmgrinfo_pkginfo_h handle;
1009
1010         ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(item->pkgid, item->uid,
1011                         &handle);
1012         if (ret < 0) {
1013                 ERR("Failed to get handle");
1014                 return -1;
1015         }
1016
1017         ret = pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP,
1018                         __pkgcmd_app_cb, "kill", item->uid);
1019         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
1020         if (ret < 0) {
1021                 ERR("pkgmgrinfo_appinfo_get_list() failed");
1022                 return -1;
1023         }
1024
1025         return 0;
1026 }
1027
1028 static int __process_check(pm_dbus_msg *item)
1029 {
1030         int ret;
1031         pkgmgrinfo_pkginfo_h handle;
1032
1033         ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(item->pkgid, item->uid,
1034                         &handle);
1035         if (ret < 0) {
1036                 ERR("Failed to get handle");
1037                 return -1;
1038         }
1039
1040         ret = pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP,
1041                         __pkgcmd_app_cb, "check", item->uid);
1042         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
1043         if (ret < 0) {
1044                 ERR("pkgmgrinfo_appinfo_get_list() failed");
1045                 return -1;
1046         }
1047
1048         return 0;
1049 }
1050
1051 static int __process_generate_license_request(pm_dbus_msg *item)
1052 {
1053         int ret;
1054         char *resp_data;
1055         char req_data[MAX_PKG_ARGS_LEN];
1056         unsigned int req_data_len;
1057         char license_url[MAX_PKG_ARGS_LEN];
1058         unsigned int license_url_len;
1059
1060         resp_data = item->args;
1061         req_data_len = sizeof(req_data);
1062         license_url_len = sizeof(license_url);
1063
1064         ret = drm_tizen_generate_license_request(resp_data, strlen(resp_data),
1065                         req_data, &req_data_len, license_url, &license_url_len);
1066         if (ret != TADC_SUCCESS) {
1067                 ERR("drm_tizen_generate_license_request failed: %d", ret);
1068                 __return_value_to_caller(item->req_id, g_variant_new("(iss)",
1069                                         PKGMGR_R_ESYSTEM, "", ""));
1070                 return -1;
1071         }
1072
1073         __return_value_to_caller(item->req_id,
1074                         g_variant_new("(iss)", PKGMGR_R_OK, req_data,
1075                                 license_url));
1076
1077         return 0;
1078 }
1079
1080 static int __process_register_license(pm_dbus_msg *item)
1081 {
1082         int ret;
1083         char *resp_data;
1084
1085         resp_data = item->args;
1086
1087         ret = drm_tizen_register_license(resp_data, strlen(resp_data));
1088         if (ret != TADC_SUCCESS) {
1089                 ERR("drm_tizen_register_license failed: %d", ret);
1090                 __return_value_to_caller(item->req_id,
1091                                 g_variant_new("(i)", PKGMGR_R_ESYSTEM));
1092                 return -1;
1093         }
1094
1095         __return_value_to_caller(item->req_id,
1096                         g_variant_new("(i)", PKGMGR_R_OK));
1097
1098         return 0;
1099 }
1100
1101 static int __process_decrypt_package(pm_dbus_msg *item)
1102 {
1103         int ret;
1104         char *drm_file_path;
1105         char *decrypted_file_path;
1106
1107         drm_file_path = item->pkgid;
1108         decrypted_file_path = item->args;
1109
1110         /* TODO: check ownership of decrypted file */
1111         ret = drm_tizen_decrypt_package(drm_file_path, strlen(drm_file_path),
1112                         decrypted_file_path, strlen(decrypted_file_path));
1113         if (ret != TADC_SUCCESS) {
1114                 ERR("drm_tizen_register_license failed: %d", ret);
1115                 __return_value_to_caller(item->req_id,
1116                                 g_variant_new("(i)", PKGMGR_R_ESYSTEM));
1117                 return -1;
1118         }
1119
1120         __return_value_to_caller(item->req_id,
1121                         g_variant_new("(i)", PKGMGR_R_OK));
1122
1123         return 0;
1124 }
1125
1126 static int __process_add_blacklist(pm_dbus_msg *item)
1127 {
1128         int ret;
1129
1130         ret = __add_blacklist(item->uid, item->pkgid);
1131
1132         __return_value_to_caller(item->req_id,
1133                         g_variant_new("(i)", ret));
1134
1135         return ret;
1136 }
1137
1138 static int __process_remove_blacklist(pm_dbus_msg *item)
1139 {
1140         int ret;
1141
1142         ret = __remove_blacklist(item->uid, item->pkgid);
1143
1144         __return_value_to_caller(item->req_id,
1145                         g_variant_new("(i)", ret));
1146
1147         return ret;
1148 }
1149
1150 static int __process_check_blacklist(pm_dbus_msg *item)
1151 {
1152         int ret;
1153         int result = 0;
1154
1155         ret = __check_blacklist(item->uid, item->pkgid, &result);
1156
1157         __return_value_to_caller(item->req_id,
1158                         g_variant_new("(ii)", result, ret));
1159
1160         return ret;
1161 }
1162
1163 gboolean queue_job(void *data)
1164 {
1165         pm_dbus_msg *item = NULL;
1166         backend_info *ptr;
1167         int x;
1168         int ret;
1169
1170         /* Pop a job from queue */
1171         for (x = 0, ptr = begin; x < num_of_backends; x++, ptr++) {
1172                 if (__is_backend_busy(x))
1173                         continue;
1174
1175                 item = _pm_queue_pop(x);
1176                 if (item && item->req_type != -1)
1177                         break;
1178                 free(item);
1179         }
1180
1181         /* all backend messages queue are empty or busy */
1182         if (x == num_of_backends)
1183                 return FALSE;
1184
1185         /*save pkg type and pkg name for future*/
1186         strncpy(ptr->pkgtype, item->pkg_type, MAX_PKG_TYPE_LEN-1);
1187         strncpy(ptr->pkgid, item->pkgid, MAX_PKG_NAME_LEN-1);
1188         strncpy(ptr->args, item->args, MAX_PKG_ARGS_LEN-1);
1189         memset((item->appid),0,MAX_PKG_NAME_LEN);
1190         ptr->uid = item->uid;
1191         DBG("handle request type [%d]", ptr->pid, item->req_type);
1192
1193         switch (item->req_type) {
1194         case PKGMGR_REQUEST_TYPE_INSTALL:
1195                 __set_backend_busy(x);
1196                 __set_recovery_mode(item->uid, item->pkgid, item->pkg_type);
1197                 ret = __process_install(item);
1198                 break;
1199         case PKGMGR_REQUEST_TYPE_REINSTALL:
1200                 __set_backend_busy(x);
1201                 __set_recovery_mode(item->uid, item->pkgid, item->pkg_type);
1202                 ret = __process_reinstall(item);
1203                 break;
1204         case PKGMGR_REQUEST_TYPE_UNINSTALL:
1205                 __set_backend_busy(x);
1206                 __set_recovery_mode(item->uid, item->pkgid, item->pkg_type);
1207                 ret = __process_uninstall(item);
1208                 break;
1209         case PKGMGR_REQUEST_TYPE_MOVE:
1210                 __set_backend_busy(x);
1211                 __set_recovery_mode(item->uid, item->pkgid, item->pkg_type);
1212                 ret = __process_move(item);
1213                 break;
1214         case PKGMGR_REQUEST_TYPE_ENABLE_PKG:
1215                 ret = __process_enable_pkg(item);
1216                 break;
1217         case PKGMGR_REQUEST_TYPE_DISABLE_PKG:
1218                 ret = __process_disable_pkg(item);
1219                 break;
1220         case PKGMGR_REQUEST_TYPE_ENABLE_APP:
1221                 ret = __process_enable_app(item);
1222                 break;
1223         case PKGMGR_REQUEST_TYPE_DISABLE_APP:
1224                 ret = __process_disable_app(item);
1225                 break;
1226         case PKGMGR_REQUEST_TYPE_GETSIZE:
1227                 __set_backend_busy(x);
1228                 ret = __process_getsize(item);
1229                 break;
1230         case PKGMGR_REQUEST_TYPE_CLEARDATA:
1231                 __set_backend_busy(x);
1232                 ret = __process_cleardata(item);
1233                 break;
1234         case PKGMGR_REQUEST_TYPE_CLEARCACHE:
1235                 __set_backend_busy(x);
1236                 ret = __process_clearcache(item);
1237                 break;
1238         case PKGMGR_REQUEST_TYPE_ENABLE_GLOBAL_APP_FOR_UID:
1239                 ret = __process_enable_global_app_for_uid(item);
1240                 break;
1241         case PKGMGR_REQUEST_TYPE_DISABLE_GLOBAL_APP_FOR_UID:
1242                 ret = __process_disable_global_app_for_uid(item);
1243                 break;
1244         case PKGMGR_REQUEST_TYPE_KILL:
1245                 ret = __process_kill(item);
1246                 break;
1247         case PKGMGR_REQUEST_TYPE_CHECK:
1248                 ret = __process_check(item);
1249                 break;
1250         case PKGMGR_REQUEST_TYPE_GENERATE_LICENSE_REQUEST:
1251                 ret = __process_generate_license_request(item);
1252                 break;
1253         case PKGMGR_REQUEST_TYPE_REGISTER_LICENSE:
1254                 ret = __process_register_license(item);
1255                 break;
1256         case PKGMGR_REQUEST_TYPE_DECRYPT_PACKAGE:
1257                 ret = __process_decrypt_package(item);
1258                 break;
1259         case PKGMGR_REQUEST_TYPE_ADD_BLACKLIST:
1260                 ret = __process_add_blacklist(item);
1261                 break;
1262         case PKGMGR_REQUEST_TYPE_REMOVE_BLACKLIST:
1263                 ret = __process_remove_blacklist(item);
1264                 break;
1265         case PKGMGR_REQUEST_TYPE_CHECK_BLACKLIST:
1266                 ret = __process_check_blacklist(item);
1267                 break;
1268         default:
1269                 ret = -1;
1270                 break;
1271         }
1272
1273         ptr->pid = ret;
1274         free(item);
1275
1276         return FALSE;
1277 }
1278
1279 #define IS_WHITESPACE(CHAR) \
1280 ((CHAR == ' ' || CHAR == '\t' || CHAR == '\r' || CHAR == '\n') ? TRUE : FALSE)
1281
1282 void _app_str_trim(char *input)
1283 {
1284         char *trim_str = input;
1285
1286         if (input == NULL)
1287                 return;
1288
1289         while (*input != 0) {
1290                 if (!IS_WHITESPACE(*input)) {
1291                         *trim_str = *input;
1292                         trim_str++;
1293                 }
1294                 input++;
1295         }
1296
1297         *trim_str = 0;
1298         return;
1299 }
1300
1301 char *_get_backend_cmd(char *type)
1302 {
1303         FILE *fp = NULL;
1304         char buffer[1024] = { 0 };
1305         char *command = NULL;
1306         int size = 0;
1307         fp = fopen(PKG_CONF_PATH, "r");
1308         if (fp == NULL) {
1309                 return NULL;
1310         }
1311
1312         char *path = NULL;
1313         while (fgets(buffer, 1024, fp) != NULL) {
1314                 if (buffer[0] == '#')
1315                         continue;
1316
1317                 _app_str_trim(buffer);
1318
1319                 if ((path = strstr(buffer, PKG_BACKEND)) != NULL) {
1320                         DBG("buffer [%s]", buffer);
1321                         path = path + strlen(PKG_BACKEND);
1322                         DBG("path [%s]", path);
1323
1324                         command =
1325                             (char *)malloc(sizeof(char) * strlen(path) +
1326                                            strlen(type) + 1);
1327                         if (command == NULL) {
1328                                 fclose(fp);
1329                                 return NULL;
1330                         }
1331
1332                         size = strlen(path) + strlen(type) + 1;
1333                         snprintf(command, size, "%s%s", path, type);
1334                         command[strlen(path) + strlen(type)] = '\0';
1335                         DBG("command [%s]", command);
1336
1337                         if (fp != NULL)
1338                                 fclose(fp);
1339
1340                         return command;
1341                 }
1342
1343                 memset(buffer, 0x00, 1024);
1344         }
1345
1346         if (fp != NULL)
1347                 fclose(fp);
1348
1349         return NULL;            /* cannot find proper command */
1350 }
1351
1352 int main(int argc, char *argv[])
1353 {
1354         FILE *fp_status = NULL;
1355         char buf[32] = { 0, };
1356         pid_t pid;
1357         char *backend_cmd = NULL;
1358         char *backend_name = NULL;
1359         int r;
1360
1361         DBG("server start");
1362
1363         if (argv[1] && (strcmp(argv[1], "init") == 0)) {
1364                 /* if current status is "processing",
1365                    execute related backend with '-r' option */
1366                 if (!(fp_status = fopen(STATUS_FILE, "r")))
1367                         return 0;       /*if file is not exist, terminated. */
1368                 /* if processing <-- unintended termination */
1369                 if (fgets(buf, 32, fp_status) &&
1370                                 strcmp(buf, "processing") == 0) {
1371                         pid = fork();
1372                         if (pid == 0) { /* child */
1373                                 if (fgets(buf, 32, fp_status))
1374                                         backend_cmd = _get_backend_cmd(buf);
1375                                 if (!backend_cmd) {     /* if NULL, */
1376                                         DBG("fail to get backend command");
1377                                         goto err;
1378                                 }
1379                                 backend_name =
1380                                         strrchr(backend_cmd, '/');
1381                                 if (!backend_name) {
1382                                         DBG("fail to get backend name");
1383                                         goto err;
1384                                 }
1385
1386                                 execl(backend_cmd, backend_name, "-r",
1387                                                 NULL);
1388                                 if (backend_cmd)
1389                                         free(backend_cmd);
1390                                 fprintf(fp_status, " ");
1391 err:
1392                                 fclose(fp_status);
1393                                 exit(13);
1394                         } else if (pid < 0) {   /* error */
1395                                 DBG("fork fail");
1396                                 fclose(fp_status);
1397                                 return 0;
1398                         } else {        /* parent */
1399
1400                                 DBG("parent end\n");
1401                                 fprintf(fp_status, " ");
1402                                 fclose(fp_status);
1403                                 return 0;
1404                         }
1405                 }
1406         }
1407
1408         r = _pm_queue_init();
1409         if (r) {
1410                 DBG("Queue Initialization Failed\n");
1411                 return -1;
1412         }
1413
1414         r = __init_backend_info();
1415         if (r) {
1416                 DBG("backend info init failed");
1417                 return -1;
1418         }
1419
1420         r = __init_request_handler();
1421         if (r) {
1422                 ERR("dbus init failed");
1423                 return -1;
1424         }
1425
1426         if (__register_signal_handler()) {
1427                 ERR("failed to register signal handler");
1428                 return -1;
1429         }
1430
1431 #if !GLIB_CHECK_VERSION(2,35,0)
1432         g_type_init();
1433 #endif
1434         mainloop = g_main_loop_new(NULL, FALSE);
1435         if (!mainloop) {
1436                 ERR("g_main_loop_new failed");
1437                 return -1;
1438         }
1439
1440         DBG("Main loop is created.");
1441
1442         g_main_loop_run(mainloop);
1443
1444         DBG("Quit main loop.");
1445         __fini_request_handler();
1446         __fini_backend_info();
1447         _pm_queue_final();
1448
1449         DBG("package manager server terminated.");
1450
1451         return 0;
1452 }