Fork child process for the backend installer only
[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_fail_signal(char *pname, char *ptype, char *args)
207 {
208         DBG("send_fail_signal start\n");
209         gboolean ret_parse;
210         gint argcp;
211         gchar **argvp;
212         GError *gerr = NULL;
213         pkgmgr_installer *pi;
214         pi = pkgmgr_installer_new();
215         if (!pi) {
216                 DBG("Failure in creating the pkgmgr_installer object");
217                 return;
218         }
219         ret_parse = g_shell_parse_argv(args,
220                                        &argcp, &argvp, &gerr);
221         if (FALSE == ret_parse) {
222                 DBG("Failed to split args: %s", args);
223                 DBG("messsage: %s", gerr->message);
224                 pkgmgr_installer_free(pi);
225                 return;
226         }
227
228         pkgmgr_installer_receive_request(pi, argcp, argvp);
229         pkgmgr_installer_send_signal(pi, ptype, pname, "end", "fail");
230         pkgmgr_installer_free(pi);
231         return;
232 }
233
234 static gboolean pipe_io_handler(GIOChannel *io, GIOCondition cond, gpointer data)
235 {
236         int x;
237         GError *err = NULL;
238         GIOStatus s;
239         gsize len;
240         struct signal_info_t info;
241         backend_info *ptr = begin;
242
243         s = g_io_channel_read_chars(io, (gchar *)&info, sizeof(struct signal_info_t), &len, &err);
244         if (s != G_IO_STATUS_NORMAL) {
245                 ERR("Signal pipe read failed: %s", err->message);
246                 g_error_free(err);
247                 return TRUE;
248         }
249
250         for (x = 0; x < num_of_backends; x++, ptr++) {
251                 if (ptr && ptr->pid == info.pid)
252                         break;
253         }
254
255         if (x == num_of_backends) {
256                 ERR("Unknown child exit");
257                 return -1;
258         }
259
260         __set_backend_free(x);
261         __unset_recovery_mode(ptr->uid, ptr->pkgid, ptr->pkgtype);
262         if (WIFSIGNALED(info.status) || WEXITSTATUS(info.status)) {
263                 send_fail_signal(ptr->pkgid, ptr->pkgtype, ptr->args);
264                 DBG("backend[%s] exit with error", ptr->pkgtype);
265         } else {
266                 DBG("backend[%s] exit", ptr->pkgtype);
267         }
268
269         g_idle_add(queue_job, NULL);
270
271         return TRUE;
272 }
273
274 static int __init_backend_info(void)
275 {
276         backend_info *ptr;
277
278         /*Allocate memory for holding pid, pkgtype and pkgid*/
279         ptr = (backend_info*)calloc(num_of_backends, sizeof(backend_info));
280         if (ptr == NULL) {
281                 DBG("Malloc Failed\n");
282                 return -1;
283         }
284         begin = ptr;
285
286         if (pipe(pipe_sig)) {
287                 ERR("create pipe failed");
288                 return -1;
289         }
290
291         pipe_io = g_io_channel_unix_new(pipe_sig[0]);
292         g_io_channel_set_encoding(pipe_io, NULL, NULL);
293         g_io_channel_set_buffered(pipe_io, FALSE);
294         pipe_wid = g_io_add_watch(pipe_io, G_IO_IN, pipe_io_handler, NULL);
295
296         return 0;
297 }
298
299 static void __fini_backend_info(void)
300 {
301         g_source_remove(pipe_wid);
302         g_io_channel_unref(pipe_io);
303         close(pipe_sig[0]);
304         close(pipe_sig[1]);
305
306         /*Free backend info */
307         free(begin);
308 }
309
310 static void sighandler(int signo)
311 {
312         struct signal_info_t info;
313
314         info.pid = waitpid(-1, &info.status, WNOHANG);
315         if (write(pipe_sig[1], &info, sizeof(struct signal_info_t)) < 0)
316                 ERR("failed to write result: %s", strerror(errno));
317 }
318
319 static int __register_signal_handler(void)
320 {
321         static int sig_reg = 0;
322         struct sigaction act;
323
324         if (sig_reg)
325                 return 0;
326
327         act.sa_handler = sighandler;
328         sigemptyset(&act.sa_mask);
329         act.sa_flags = SA_NOCLDSTOP;
330         if (sigaction(SIGCHLD, &act, NULL) < 0) {
331                 ERR("signal: SIGCHLD failed\n");
332                 return -1;
333         }
334
335         g_timeout_add_seconds(2, exit_server, NULL);
336
337         sig_reg = 1;
338         return 0;
339 }
340
341 static int __check_backend_status_for_exit(void)
342 {
343         int i = 0;
344         for(i = 0; i < num_of_backends; i++)
345         {
346                 if (!__is_backend_busy(i))
347                         continue;
348                 else
349                         return 0;
350         }
351         return 1;
352 }
353
354 static int __check_queue_status_for_exit(void)
355 {
356         pm_queue_data *head[MAX_QUEUE_NUM] = {NULL,};
357         queue_info_map *ptr = NULL;
358         ptr = start;
359         int i = 0;
360         int c = 0;
361         int slot = -1;
362         for(i = 0; i < entries; i++)
363         {
364                 if (ptr->queue_slot <= slot) {
365                         ptr++;
366                         continue;
367                 }
368                 else {
369                         head[c] = ptr->head;
370                         slot = ptr->queue_slot;
371                         c++;
372                         ptr++;
373                 }
374         }
375         for(i = 0; i < num_of_backends; i++)
376         {
377                 if (!head[i])
378                         continue;
379                 else
380                         return 0;
381         }
382         return 1;
383 }
384
385 gboolean exit_server(void *data)
386 {
387         DBG("exit_server Start\n");
388         if (__check_backend_status_for_exit() &&
389                         __check_queue_status_for_exit()) {
390                 if (!getenv("PMS_STANDALONE")) {
391                         g_main_loop_quit(mainloop);
392                         return FALSE;
393                 }
394         }
395         return TRUE;
396 }
397
398 static int __pkgcmd_read_proc(const char *path, char *buf, int size)
399 {
400         int fd;
401         int ret;
402         if (buf == NULL || path == NULL)
403                 return -1;
404         fd = open(path, O_RDONLY);
405         if (fd < 0)
406                 return -1;
407         ret = read(fd, buf, size - 1);
408         if (ret <= 0) {
409                 close(fd);
410                 return -1;
411         } else
412                 buf[ret] = 0;
413         close(fd);
414         return ret;
415 }
416
417 static int __pkgcmd_find_pid_by_cmdline(const char *dname,
418                         const char *cmdline, const char *apppath)
419 {
420         int pid = 0;
421
422         if (strcmp(cmdline, apppath) == 0) {
423                 pid = atoi(dname);
424                 if (pid != getpgid(pid))
425                         pid = 0;
426         }
427         return pid;
428 }
429
430 static int __pkgcmd_proc_iter_kill_cmdline(const char *apppath, int option)
431 {
432         DIR *dp;
433         struct dirent *dentry;
434         int pid;
435         int ret;
436         char buf[1024] = {'\0'};
437         int pgid;
438
439         dp = opendir("/proc");
440         if (dp == NULL) {
441                 return -1;
442         }
443
444         while ((dentry = readdir(dp)) != NULL) {
445                 if (!isdigit(dentry->d_name[0]))
446                         continue;
447
448                 snprintf(buf, sizeof(buf), "/proc/%s/cmdline", dentry->d_name);
449                 ret = __pkgcmd_read_proc(buf, buf, sizeof(buf));
450                 if (ret <= 0)
451                         continue;
452
453                 pid = __pkgcmd_find_pid_by_cmdline(dentry->d_name, buf, apppath);
454                 if (pid > 0) {
455                         if (option == 0) {
456                                 closedir(dp);
457                                 return pid;
458                         }
459                         pgid = getpgid(pid);
460                         if (pgid <= 1) {
461                                 closedir(dp);
462                                 return -1;
463                         }
464                         if (killpg(pgid, SIGKILL) < 0) {
465                                 closedir(dp);
466                                 return -1;
467                         }
468                         closedir(dp);
469                         return pid;
470                 }
471         }
472         closedir(dp);
473         return 0;
474 }
475
476 static void __make_pid_info_file(char *req_key, int pid)
477 {
478         FILE* file;
479         int fd;
480         char buf[MAX_PKG_TYPE_LEN] = {0};
481         char info_file[PATH_MAX] = {'\0'};
482
483         if(req_key == NULL)
484                 return;
485
486         snprintf(info_file, PATH_MAX, "/tmp/pkgmgr/%s", req_key);
487
488         DBG("info_path(%s)", info_file);
489         file = fopen(info_file, "w");
490         if (file == NULL) {
491                 ERR("Couldn't open the file(%s)", info_file);
492                 return;
493         }
494
495         snprintf(buf, MAX_PKG_TYPE_LEN, "%d\n", pid);
496         fwrite(buf, 1, strlen(buf), file);
497
498         fflush(file);
499         fd = fileno(file);
500         fsync(fd);
501         fclose(file);
502 }
503
504 static int __pkgcmd_app_cb(const pkgmgrinfo_appinfo_h handle, void *user_data)
505 {
506         char *pkgid;
507         char *exec;
508         int ret;
509         int pid = -1;
510
511         if (handle == NULL) {
512                 perror("appinfo handle is NULL\n");
513                 exit(1);
514         }
515         ret = pkgmgrinfo_appinfo_get_exec(handle, &exec);
516         if (ret) {
517                 perror("Failed to get app exec path\n");
518                 exit(1);
519         }
520         ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgid);
521         if (ret) {
522                 perror("Failed to get pkgid\n");
523                 exit(1);
524         }
525
526         if (strcmp(user_data, "kill") == 0)
527                 pid = __pkgcmd_proc_iter_kill_cmdline(exec, 1);
528         else if(strcmp(user_data, "check") == 0)
529                 pid = __pkgcmd_proc_iter_kill_cmdline(exec, 0);
530
531         __make_pid_info_file(pkgid, pid);
532
533         return 0;
534 }
535
536 void free_user_context(user_ctx* ctx)
537 {
538         char **env = NULL;
539         int i = 0;
540         if (!ctx)
541                 return;
542         env = ctx->env;
543         //env variable ends by NULL element
544         while (env[i]) {
545                 free(env[i]);
546                 i++;
547         }
548         free(env);
549         env = NULL;
550         free(ctx);
551 }
552
553 int set_environement(user_ctx *ctx)
554 {
555         int i = 0;
556         int res = 0;
557         char **env = NULL;
558         if (!ctx)
559                 return -1;;
560         if (setgid(ctx->gid)) {
561                 ERR("setgid failed: %d", errno);
562                 return -1;
563         }
564         if (setuid(ctx->uid)) {
565                 ERR("setuid failed: %d", errno);
566                 return -1;
567         }
568         env = ctx->env;
569         //env variable ends by NULL element
570         while (env[i]) {
571                 if (putenv(env[i]) != 0)
572                         res = -1;
573                 i++;
574         }
575         return res;
576 }
577
578 user_ctx* get_user_context(uid_t uid)
579 {
580         /* we can use getpwnam because this is used only after a
581          * fork and just before an execv
582          * No concurrencial call can corrupt the data
583          * returned by getpwuid
584          */
585         user_ctx *context_res;
586         char **env = NULL;
587         struct passwd * pwd;
588         int len;
589         int ret = 0;
590
591         pwd = getpwuid(uid);
592         if (!pwd)
593                 return NULL;
594
595         do {
596                 context_res = (user_ctx *)malloc(sizeof(user_ctx));
597                 if (!context_res) {
598                         ret = -1;
599                         break;
600                 }
601                 env = (char**)malloc(3* sizeof(char *));
602                 if (!env) {
603                         ret = -1;
604                         break;
605                 }
606                 // Build environment context
607                 len = snprintf(NULL,0, "HOME=%s", pwd->pw_dir);
608                 env[0] = (char*)malloc((len + 1)* sizeof(char));
609                 if(env[0] == NULL) {
610                         ret = -1;
611                         break;
612                 }
613                 sprintf(env[0], "HOME=%s", pwd->pw_dir);
614                 len = snprintf(NULL,0, "USER=%s", pwd->pw_name);
615                 env[1] = (char*)malloc((len + 1)* sizeof(char));
616                 if(env[1] == NULL) {
617                         ret = -1;
618                         break;
619                 }
620
621                 sprintf(env[1], "USER=%s", pwd->pw_name);
622                 env[2] = NULL;
623         } while (0);
624
625         if (ret == -1) {
626                 free(context_res);
627                 context_res = NULL;
628                 int i = 0;
629                 //env variable ends by NULL element
630                 while (env && env[i]) {
631                         free(env[i]);
632                         i++;
633                 }
634                 free(env);
635                 env = NULL;
636         } else {
637                 context_res->env = env;
638                 context_res->uid = uid;
639                 context_res->gid = pwd->pw_gid;
640         }
641         return context_res;
642 }
643
644 static char **__generate_argv(const char *args)
645 {
646         /* Create args vector
647          * req_id + pkgid + args
648          *
649          * vector size = # of args +
650          *(req_id + pkgid + NULL termination = 3)
651          * Last value must be NULL for execv.
652          */
653         gboolean ret_parse;
654         gint argcp;
655         gchar **argvp;
656         GError *gerr = NULL;
657         int i;
658
659         ret_parse = g_shell_parse_argv(args,
660                         &argcp, &argvp, &gerr);
661         if (FALSE == ret_parse) {
662                 DBG("Failed to split args: %s", args);
663                 DBG("messsage: %s", gerr->message);
664                 exit(1);
665         }
666
667         /* dbg */
668         for (i = 0; i < argcp; i++)
669                 DBG(">>>>>> argsv[%d]=%s", i, argvp[i]);
670
671         return argvp;
672 }
673
674 void __set_environment(gpointer user_data)
675 {
676         user_ctx *ctx = (user_ctx *)user_data;
677
678         if (set_environement(ctx))
679                 DBG("Failed to set env for the user : %d", ctx->uid);
680 }
681
682 static int __exec_with_arg_vector(const char *cmd, char **argv, uid_t uid)
683 {
684         user_ctx* user_context;
685         GError *error = NULL;
686         gboolean ret;
687         int pid;
688
689         user_context = get_user_context(uid);
690         if (!user_context) {
691                 DBG("Failed to getenv for the user : %d", uid);
692                 return -1;
693         }
694
695         ret = g_spawn_async(NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
696                         __set_environment, (gpointer)user_context, &pid,
697                         &error);
698         if (ret != TRUE) {
699                 ERR("Failed to excute backend: %s", error->message);
700                 g_error_free(error);
701         }
702
703         free_user_context(user_context);
704
705         return pid;
706 }
707
708 static int __process_install(pm_dbus_msg *item)
709 {
710         char *backend_cmd;
711         char **argv;
712         char args[MAX_PKG_ARGS_LEN] = {'\0', };
713         int pid;
714
715         backend_cmd = _get_backend_cmd(item->pkg_type);
716         if (backend_cmd == NULL)
717                 return -1;
718
719         snprintf(args, sizeof(args), "%s -k %s -i %s %s", backend_cmd,
720                         item->req_id, item->pkgid, item->args);
721
722         argv = __generate_argv(args);
723
724         pid = __exec_with_arg_vector(backend_cmd, argv, item->uid);
725         g_strfreev(argv);
726         free(backend_cmd);
727
728         return pid;
729 }
730
731 static int __process_reinstall(pm_dbus_msg *item)
732 {
733         char *backend_cmd;
734         char **argv;
735         char args[MAX_PKG_ARGS_LEN];
736         int pid;
737
738         backend_cmd = _get_backend_cmd(item->pkg_type);
739         if (backend_cmd == NULL)
740                 return -1;
741
742         snprintf(args, sizeof(args), "%s -k %s -r %s", backend_cmd,
743                         item->req_id, item->pkgid);
744         argv = __generate_argv(args);
745
746         pid = __exec_with_arg_vector(backend_cmd, argv, item->uid);
747
748         g_strfreev(argv);
749         free(backend_cmd);
750
751         return pid;
752 }
753
754 static int __process_uninstall(pm_dbus_msg *item)
755 {
756         char *backend_cmd;
757         char **argv;
758         char args[MAX_PKG_ARGS_LEN];
759         int pid;
760
761         backend_cmd = _get_backend_cmd(item->pkg_type);
762         if (backend_cmd == NULL)
763                 return -1;
764
765         snprintf(args, sizeof(args), "%s -k %s -d %s", backend_cmd,
766                         item->req_id, item->pkgid);
767         argv = __generate_argv(args);
768
769         pid = __exec_with_arg_vector(backend_cmd, argv, item->uid);
770
771         g_strfreev(argv);
772         free(backend_cmd);
773
774         return pid;
775 }
776
777 static int __process_move(pm_dbus_msg *item)
778 {
779         char *backend_cmd;
780         char **argv;
781         char args[MAX_PKG_ARGS_LEN];
782         int pid;
783
784         backend_cmd = _get_backend_cmd(item->pkg_type);
785         if (backend_cmd == NULL)
786                 return -1;
787
788         /* TODO: set movetype */
789         snprintf(args, sizeof(args), "%s -k %s -m %s -t %s", backend_cmd,
790                         item->req_id, item->pkgid, item->args);
791         argv = __generate_argv(args);
792
793         pid = __exec_with_arg_vector(backend_cmd, argv, item->uid);
794
795         g_strfreev(argv);
796         free(backend_cmd);
797
798         return pid;
799 }
800
801 static int __process_enable(pm_dbus_msg *item)
802 {
803         /* TODO */
804         return 0;
805 }
806
807 static int __process_disable(pm_dbus_msg *item)
808 {
809         /* TODO */
810         return 0;
811 }
812
813 static int __process_enable_global_app(pm_dbus_msg *item)
814 {
815         pkgmgr_parser_update_global_app_disable_info_in_db(item->pkgid, item->uid, 0);
816         return 0;
817 }
818
819 static int __process_disable_global_app(pm_dbus_msg *item)
820 {
821         pkgmgr_parser_update_global_app_disable_info_in_db(item->pkgid, item->uid, 1);
822         return 0;
823 }
824
825 static int __process_getsize(pm_dbus_msg *item)
826 {
827         char **argv;
828         char args[MAX_PKG_ARGS_LEN];
829         int pid;
830
831         snprintf(args, sizeof(args), "%s %s -k %s", item->pkgid, item->args,
832                         item->req_id);
833         argv = __generate_argv(args);
834         pid = __exec_with_arg_vector("/usr/bin/pkg_getsize", argv, item->uid);
835
836         g_strfreev(argv);
837
838         return pid;
839 }
840
841 static int __process_cleardata(pm_dbus_msg *item)
842 {
843         char *backend_cmd;
844         char **argv;
845         char args[MAX_PKG_ARGS_LEN];
846         int pid;
847
848         backend_cmd = _get_backend_cmd(item->pkg_type);
849         if (backend_cmd == NULL)
850                 return -1;
851
852         /* TODO: set movetype */
853         snprintf(args, sizeof(args), "%s -k %s -c %s", backend_cmd,
854                         item->req_id, item->pkgid);
855         argv = __generate_argv(args);
856
857         pid = __exec_with_arg_vector(backend_cmd, argv, item->uid);
858
859         g_strfreev(argv);
860         free(backend_cmd);
861
862         return pid;
863 }
864
865 static int __process_clearcache(pm_dbus_msg *item)
866 {
867         char **argv;
868         char args[MAX_PKG_ARGS_LEN];
869         int pid;
870
871         snprintf(args, sizeof(args), "%s", item->pkgid);
872         argv = __generate_argv(args);
873         pid = __exec_with_arg_vector("/usr/bin/pkg_clearcache", argv, item->uid);
874
875         g_strfreev(argv);
876
877         return pid;
878 }
879
880 static int __process_kill(pm_dbus_msg *item)
881 {
882         int ret;
883         pkgmgrinfo_pkginfo_h handle;
884
885         ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(item->pkgid, item->uid,
886                         &handle);
887         if (ret < 0) {
888                 ERR("Failed to get handle");
889                 return -1;
890         }
891
892         ret = pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP,
893                         __pkgcmd_app_cb, "kill", item->uid);
894         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
895         if (ret < 0) {
896                 ERR("pkgmgrinfo_appinfo_get_list() failed");
897                 return -1;
898         }
899
900         return 0;
901 }
902
903 static int __process_check(pm_dbus_msg *item)
904 {
905         int ret;
906         pkgmgrinfo_pkginfo_h handle;
907
908         ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(item->pkgid, item->uid,
909                         &handle);
910         if (ret < 0) {
911                 ERR("Failed to get handle");
912                 return -1;
913         }
914
915         ret = pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP,
916                         __pkgcmd_app_cb, "check", item->uid);
917         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
918         if (ret < 0) {
919                 ERR("pkgmgrinfo_appinfo_get_list() failed");
920                 return -1;
921         }
922
923         return 0;
924 }
925
926 static int __process_generate_license_request(pm_dbus_msg *item)
927 {
928         int ret;
929         char *resp_data;
930         char req_data[MAX_PKG_ARGS_LEN];
931         unsigned int req_data_len;
932         char license_url[MAX_PKG_ARGS_LEN];
933         unsigned int license_url_len;
934
935         resp_data = item->args;
936         req_data_len = sizeof(req_data);
937         license_url_len = sizeof(license_url);
938
939         ret = drm_tizen_generate_license_request(resp_data, strlen(resp_data),
940                         req_data, &req_data_len, license_url, &license_url_len);
941         if (ret != TADC_SUCCESS) {
942                 ERR("drm_tizen_generate_license_request failed: %d", ret);
943                 __return_value_to_caller(item->req_id, g_variant_new("(iss)",
944                                         PKGMGR_R_ESYSTEM, "", ""));
945                 return -1;
946         }
947
948         __return_value_to_caller(item->req_id,
949                         g_variant_new("(iss)", PKGMGR_R_OK, req_data,
950                                 license_url));
951
952         return 0;
953 }
954
955 static int __process_register_license(pm_dbus_msg *item)
956 {
957         int ret;
958         char *resp_data;
959
960         resp_data = item->args;
961
962         ret = drm_tizen_register_license(resp_data, strlen(resp_data));
963         if (ret != TADC_SUCCESS) {
964                 ERR("drm_tizen_register_license failed: %d", ret);
965                 __return_value_to_caller(item->req_id,
966                                 g_variant_new("(i)", PKGMGR_R_ESYSTEM));
967                 return -1;
968         }
969
970         __return_value_to_caller(item->req_id,
971                         g_variant_new("(i)", PKGMGR_R_OK));
972
973         return 0;
974 }
975
976 static int __process_decrypt_package(pm_dbus_msg *item)
977 {
978         int ret;
979         char *drm_file_path;
980         char *decrypted_file_path;
981
982         drm_file_path = item->pkgid;
983         decrypted_file_path = item->args;
984
985         /* TODO: check ownership of decrypted file */
986         ret = drm_tizen_decrypt_package(drm_file_path, strlen(drm_file_path),
987                         decrypted_file_path, strlen(decrypted_file_path));
988         if (ret != TADC_SUCCESS) {
989                 ERR("drm_tizen_register_license failed: %d", ret);
990                 __return_value_to_caller(item->req_id,
991                                 g_variant_new("(i)", PKGMGR_R_ESYSTEM));
992                 return -1;
993         }
994
995         __return_value_to_caller(item->req_id,
996                         g_variant_new("(i)", PKGMGR_R_OK));
997
998         return 0;
999 }
1000
1001 gboolean queue_job(void *data)
1002 {
1003         pm_dbus_msg *item = NULL;
1004         backend_info *ptr;
1005         int x;
1006         int ret;
1007
1008         /* Pop a job from queue */
1009         for (x = 0, ptr = begin; x < num_of_backends; x++, ptr++) {
1010                 if (__is_backend_busy(x))
1011                         continue;
1012
1013                 item = _pm_queue_pop(x);
1014                 if (item && item->req_type != -1)
1015                         break;
1016                 free(item);
1017         }
1018
1019         /* all backend messages queue are empty or busy */
1020         if (x == num_of_backends)
1021                 return FALSE;
1022
1023         __set_backend_busy(x);
1024         __set_recovery_mode(item->uid, item->pkgid, item->pkg_type);
1025
1026         /*save pkg type and pkg name for future*/
1027         strncpy(ptr->pkgtype, item->pkg_type, MAX_PKG_TYPE_LEN-1);
1028         strncpy(ptr->pkgid, item->pkgid, MAX_PKG_NAME_LEN-1);
1029         strncpy(ptr->args, item->args, MAX_PKG_ARGS_LEN-1);
1030         ptr->uid = item->uid;
1031         DBG("handle request type [%d]", ptr->pid, item->req_type);
1032
1033         switch (item->req_type) {
1034         case PKGMGR_REQUEST_TYPE_INSTALL:
1035                 ret = __process_install(item);
1036                 break;
1037         case PKGMGR_REQUEST_TYPE_REINSTALL:
1038                 ret = __process_reinstall(item);
1039                 break;
1040         case PKGMGR_REQUEST_TYPE_UNINSTALL:
1041                 ret = __process_uninstall(item);
1042                 break;
1043         case PKGMGR_REQUEST_TYPE_MOVE:
1044                 ret = __process_move(item);
1045                 break;
1046         case PKGMGR_REQUEST_TYPE_ENABLE:
1047                 ret = __process_enable(item);
1048                 break;
1049         case PKGMGR_REQUEST_TYPE_DISABLE:
1050                 ret = __process_disable(item);
1051                 break;
1052         case PKGMGR_REQUEST_TYPE_GETSIZE:
1053                 ret = __process_getsize(item);
1054                 break;
1055         case PKGMGR_REQUEST_TYPE_CLEARDATA:
1056                 ret = __process_cleardata(item);
1057                 break;
1058         case PKGMGR_REQUEST_TYPE_CLEARCACHE:
1059                 ret = __process_clearcache(item);
1060                 break;
1061         case PKGMGR_REQUEST_TYPE_ENABLE_GLOBAL_APP:
1062                 ret = __process_enable_global_app(item);
1063                 break;
1064         case PKGMGR_REQUEST_TYPE_DISABLE_GLOBAL_APP:
1065                 ret = __process_disable_global_app(item);
1066                 break;
1067         case PKGMGR_REQUEST_TYPE_KILL:
1068                 ret = __process_kill(item);
1069                 break;
1070         case PKGMGR_REQUEST_TYPE_CHECK:
1071                 ret = __process_check(item);
1072                 break;
1073         case PKGMGR_REQUEST_TYPE_GENERATE_LICENSE_REQUEST:
1074                 ret = __process_generate_license_request(item);
1075                 break;
1076         case PKGMGR_REQUEST_TYPE_REGISTER_LICENSE:
1077                 ret = __process_register_license(item);
1078                 break;
1079         case PKGMGR_REQUEST_TYPE_DECRYPT_PACKAGE:
1080                 ret = __process_decrypt_package(item);
1081                 break;
1082         default:
1083                 ret = -1;
1084                 break;
1085         }
1086
1087         ptr->pid = ret;
1088         free(item);
1089
1090         return FALSE;
1091 }
1092
1093 #define IS_WHITESPACE(CHAR) \
1094 ((CHAR == ' ' || CHAR == '\t' || CHAR == '\r' || CHAR == '\n') ? TRUE : FALSE)
1095
1096 void _app_str_trim(char *input)
1097 {
1098         char *trim_str = input;
1099
1100         if (input == NULL)
1101                 return;
1102
1103         while (*input != 0) {
1104                 if (!IS_WHITESPACE(*input)) {
1105                         *trim_str = *input;
1106                         trim_str++;
1107                 }
1108                 input++;
1109         }
1110
1111         *trim_str = 0;
1112         return;
1113 }
1114
1115 char *_get_backend_cmd(char *type)
1116 {
1117         FILE *fp = NULL;
1118         char buffer[1024] = { 0 };
1119         char *command = NULL;
1120         int size = 0;
1121         fp = fopen(PKG_CONF_PATH, "r");
1122         if (fp == NULL) {
1123                 return NULL;
1124         }
1125
1126         char *path = NULL;
1127         while (fgets(buffer, 1024, fp) != NULL) {
1128                 if (buffer[0] == '#')
1129                         continue;
1130
1131                 _app_str_trim(buffer);
1132
1133                 if ((path = strstr(buffer, PKG_BACKEND)) != NULL) {
1134                         DBG("buffer [%s]", buffer);
1135                         path = path + strlen(PKG_BACKEND);
1136                         DBG("path [%s]", path);
1137
1138                         command =
1139                             (char *)malloc(sizeof(char) * strlen(path) +
1140                                            strlen(type) + 1);
1141                         if (command == NULL) {
1142                                 fclose(fp);
1143                                 return NULL;
1144                         }
1145
1146                         size = strlen(path) + strlen(type) + 1;
1147                         snprintf(command, size, "%s%s", path, type);
1148                         command[strlen(path) + strlen(type)] = '\0';
1149                         DBG("command [%s]", command);
1150
1151                         if (fp != NULL)
1152                                 fclose(fp);
1153
1154                         return command;
1155                 }
1156
1157                 memset(buffer, 0x00, 1024);
1158         }
1159
1160         if (fp != NULL)
1161                 fclose(fp);
1162
1163         return NULL;            /* cannot find proper command */
1164 }
1165
1166 int main(int argc, char *argv[])
1167 {
1168         FILE *fp_status = NULL;
1169         char buf[32] = { 0, };
1170         pid_t pid;
1171         char *backend_cmd = NULL;
1172         char *backend_name = NULL;
1173         int r;
1174
1175         DBG("server start");
1176
1177         if (argv[1] && (strcmp(argv[1], "init") == 0)) {
1178                 /* if current status is "processing",
1179                    execute related backend with '-r' option */
1180                 if (!(fp_status = fopen(STATUS_FILE, "r")))
1181                         return 0;       /*if file is not exist, terminated. */
1182                 /* if processing <-- unintended termination */
1183                 if (fgets(buf, 32, fp_status) &&
1184                                 strcmp(buf, "processing") == 0) {
1185                         pid = fork();
1186                         if (pid == 0) { /* child */
1187                                 if (fgets(buf, 32, fp_status))
1188                                         backend_cmd = _get_backend_cmd(buf);
1189                                 if (!backend_cmd) {     /* if NULL, */
1190                                         DBG("fail to get backend command");
1191                                         goto err;
1192                                 }
1193                                 backend_name =
1194                                         strrchr(backend_cmd, '/');
1195                                 if (!backend_name) {
1196                                         DBG("fail to get backend name");
1197                                         goto err;
1198                                 }
1199
1200                                 execl(backend_cmd, backend_name, "-r",
1201                                                 NULL);
1202                                 if (backend_cmd)
1203                                         free(backend_cmd);
1204                                 fprintf(fp_status, " ");
1205 err:
1206                                 fclose(fp_status);
1207                                 exit(13);
1208                         } else if (pid < 0) {   /* error */
1209                                 DBG("fork fail");
1210                                 fclose(fp_status);
1211                                 return 0;
1212                         } else {        /* parent */
1213
1214                                 DBG("parent end\n");
1215                                 fprintf(fp_status, " ");
1216                                 fclose(fp_status);
1217                                 return 0;
1218                         }
1219                 }
1220         }
1221
1222         r = _pm_queue_init();
1223         if (r) {
1224                 DBG("Queue Initialization Failed\n");
1225                 return -1;
1226         }
1227
1228         r = __init_backend_info();
1229         if (r) {
1230                 DBG("backend info init failed");
1231                 return -1;
1232         }
1233
1234         r = __init_request_handler();
1235         if (r) {
1236                 ERR("dbus init failed");
1237                 return -1;
1238         }
1239
1240         if (__register_signal_handler()) {
1241                 ERR("failed to register signal handler");
1242                 return -1;
1243         }
1244
1245 #if !GLIB_CHECK_VERSION(2,35,0)
1246         g_type_init();
1247 #endif
1248         mainloop = g_main_loop_new(NULL, FALSE);
1249         if (!mainloop) {
1250                 ERR("g_main_loop_new failed");
1251                 return -1;
1252         }
1253
1254         DBG("Main loop is created.");
1255
1256         g_main_loop_run(mainloop);
1257
1258         DBG("Quit main loop.");
1259         __fini_request_handler();
1260         __fini_backend_info();
1261         _pm_queue_final();
1262
1263         DBG("package manager server terminated.");
1264
1265         return 0;
1266 }