Update source from tizen 2.3
[platform/core/base/rpm-installer.git] / backend-lib / src / librpm.c
1 /*
2  * rpm-installer
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
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/time.h>
28 /*rpm specific headers*/
29 #include <rpmlib.h>
30 #include <header.h>
31 #include <rpmts.h>
32 #include <rpmdb.h>
33 #include <vconf.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <ctype.h>
37
38 /* For multi-user support */
39 #include <tzplatform_config.h>
40
41 #include "librpminternals.h"
42 #include "rpm-installer-util.h"
43
44 #define BASEDIR                                         tzplatform_getenv(TZ_SYS_SHARE)
45 #define USER_APP_FOLDER                                 tzplatform_getenv(TZ_USER_APP)
46 #define BUFFSIZE                                                1024
47
48 static int __xsystem(const char *argv[])
49 {
50         int status = 0;
51         pid_t pid;
52         pid = fork();
53         switch (pid) {
54         case -1:
55                 perror("fork failed");
56                 return -1;
57         case 0:
58                 /* child */
59                 execvp(argv[0], (char *const *)argv);
60                 _exit(-1);
61         default:
62                 /* parent */
63                 break;
64         }
65         if (waitpid(pid, &status, 0) == -1) {
66                 perror("waitpid failed");
67                 return -1;
68         }
69         if (WIFSIGNALED(status)) {
70                 perror("signal");
71                 return -1;
72         }
73         if (!WIFEXITED(status)) {
74                 /* shouldn't happen */
75                 perror("should not happen");
76                 return -1;
77         }
78         return WEXITSTATUS(status);
79 }
80
81 static void __str_trim(char *input)
82 {
83         char *trim_str = input;
84
85         if (input == NULL)
86                 return;
87
88         while (*input != 0) {
89                 if (!isspace(*input)) {
90                         *trim_str = *input;
91                         trim_str++;
92                 }
93                 input++;
94         }
95
96         *trim_str = 0;
97         return;
98 }
99
100 static char *__get_value(const char *pBuf, const char *pKey, int seperator)
101 {
102         const char *p = NULL;
103         const char *pStart = NULL;
104         const char *pEnd = NULL;
105
106         p = strstr(pBuf, pKey);
107         if (p == NULL)
108                 return NULL;
109
110         pStart = p + strlen(pKey) + 1;
111         pEnd = strchr(pStart, seperator);
112         if (pEnd == NULL)
113                 return NULL;
114
115         size_t len = pEnd - pStart;
116         if (len <= 0)
117                 return NULL;
118
119         char *pRes = (char*)malloc(len + 1);
120         if(pRes == NULL){
121                 _LOGE("malloc() failed.");
122                 return NULL;
123         }
124
125         strncpy(pRes, pStart, len);
126         pRes[len] = 0;
127
128         _LOGD("key = [%s], value = [%s]", pKey, pRes);
129         return pRes;
130 }
131
132 static int __read_pkg_detail_info(const char *pkg_path, const char *manifest, package_manager_pkg_detail_info_t *pkg_detail_info)
133 {
134         int ret = 0;
135         FILE *fp = NULL;
136         char buf[BUFFSIZE] = {0};
137         char icon_path[BUFFSIZE] = {0};
138         char *pkgid = NULL;
139         char *version = NULL;
140         char *label = NULL;
141         char *icon = NULL;
142 //      char *api_version = NULL;
143
144         if(pkg_detail_info == NULL){
145                 _LOGE("pkg_details_info is NULL");
146                 return -1;
147         }
148
149         fp = fopen(manifest, "r");
150         if (fp == NULL) {
151                 _LOGE("fopen(%s) failed.", manifest);
152                 return -1;
153         }
154
155         while (fgets(buf, BUFFSIZE, fp) != NULL) {
156                 __str_trim(buf);
157
158                 if (strstr(buf, "?xml") != NULL)
159                 {
160                         memset(buf, 0x00, BUFFSIZE);
161                         continue;
162                 }
163
164                 if (pkgid == NULL) {
165                         pkgid = __get_value(buf, "package=", '"');
166                 }
167
168                 if (version == NULL) {
169                         version = strstr(buf, "version=");
170                         /* if the result substring is "api-version", search again */
171                         if (buf != version && *(char *)(version - 1) == '-') {
172                                 version = version + strlen("api-version=");
173                                 version = __get_value(version, "version=", '"');
174                         } else {
175                                 version = __get_value(buf, "version=", '"');
176                         }
177                 }
178 /*
179                 if (api_version == NULL) {
180                         api_version = __get_value(buf, "api-version=", '"');
181                 }
182 */
183                 if (label == NULL) {
184                         label = __get_value(buf, "<label", '<');
185                 }
186
187                 if (icon == NULL) {
188                         icon = __get_value(buf, "<icon", '<');
189                 }
190
191                 char *privilege = __get_value(buf, "<privilege", '<');
192                 if (privilege != NULL) {
193                         pkg_detail_info->privilege_list = g_list_append(pkg_detail_info->privilege_list, privilege);
194                 }
195
196                 memset(buf, 0x00, BUFFSIZE);
197         }
198         fclose(fp);
199
200         strncpy(pkg_detail_info->pkg_type, "coretpk", strlen("coretpk"));
201
202         if (pkgid) {
203                 strncpy(pkg_detail_info->pkgid, pkgid, strlen(pkgid));
204                 strncpy(pkg_detail_info->pkg_name, pkgid, strlen(pkgid));
205
206                 free(pkgid);
207         }
208
209         if (version) {
210                 strncpy(pkg_detail_info->version, version, strlen(version));
211
212                 free(version);
213         }
214 /*
215         if (api_version) {
216                 strncpy(pkg_detail_info->api_version, api_version, strlen(api_version));
217
218                 free(api_version);
219         }
220 */
221         if (label) {
222                 strncpy(pkg_detail_info->label, label, strlen(label));
223
224                 free(label);
225         }
226
227         if (icon) {
228                 snprintf(icon_path, BUFFSIZE, "shared/res/%s", icon);
229                 const char *unzip_icon_argv[] = { "/usr/bin/unzip", pkg_path, icon_path, "-d", "/tmp/coretpk-unzip", NULL };
230
231                 ret = __xsystem(unzip_icon_argv);
232                 if (ret == 0) {
233                         struct stat fileinfo;
234
235                         memset(icon_path, 0x00, BUFFSIZE);
236                         snprintf(icon_path, BUFFSIZE, "/tmp/coretpk-unzip/shared/res/%s", icon);
237
238                         if (lstat(icon_path, &fileinfo) < 0) {
239                                 _LOGE("lstat(%s) failed.", icon_path);
240                         } else {
241                                 FILE *icon_fp = NULL;
242                                 pkg_detail_info->icon_size = fileinfo.st_size + 1;
243                                 pkg_detail_info->icon_buf = (char*) calloc(1, (sizeof(char) * pkg_detail_info->icon_size));
244                                 if(pkg_detail_info->icon_buf == NULL){
245                                         _LOGE("calloc failed!!");
246                                         free(icon);
247                                         return -1;
248                                 }
249
250                                 icon_fp = fopen(icon_path, "r");
251                                 if (icon_fp) {
252                                         int readbyte = fread(pkg_detail_info->icon_buf, 1, pkg_detail_info->icon_size - 1, icon_fp);
253                                         _LOGD("icon_size = [%d], readbyte = [%d]", pkg_detail_info->icon_size, readbyte);
254
255                                         fclose(icon_fp);
256                                 } else {
257                                         _LOGE("fopen(%s) failed.", icon_path);
258                                 }
259                         }
260                 } else {
261                         _LOGE("unzip(%s) failed.", icon_path);
262                 }
263
264                 free(icon);
265         }
266
267         return 0;
268 }
269
270 static int __is_core_tpk_app(const char *pkg_path, package_manager_pkg_detail_info_t *pkg_detail_info)
271 {
272         int ret = 0;
273         const char *unzip_argv[] = { "/usr/bin/unzip", pkg_path, "tizen-manifest.xml", "-d", "/tmp/coretpk-unzip", NULL };
274         const char *delete_argv[] = { "/bin/rm", "-rf", "/tmp/coretpk-unzip", NULL };
275
276         __xsystem(delete_argv);
277
278         ret = mkdir("/tmp/coretpk-unzip", 0755);
279         if (ret != 0) {
280                 _LOGE("mkdir(/tmp/coretpk-unzip) failed.");
281                 return -1;
282         }
283
284         /* In case of installation request, pkgid contains the pkgpath */
285         ret = __xsystem(unzip_argv);
286         if (ret == 0) {
287                 _LOGD("[%s] is core-tpk.", pkg_path);
288
289                 if (access("/tmp/coretpk-unzip/tizen-manifest.xml", R_OK) == 0) {
290                         _LOGD("tizen-manifest.xml is found.");
291                 } else {
292                         _LOGE("tizen-manifest.xml is not found.");
293                         __xsystem(delete_argv);
294                         return -1;
295                 }
296
297                 ret = __read_pkg_detail_info(pkg_path, "/tmp/coretpk-unzip/tizen-manifest.xml", pkg_detail_info);
298                 if (ret != 0) {
299                         _LOGE("__read_pkg_detail_info() failed. [%s]", pkg_path);
300                         __xsystem(delete_argv);
301                         return -1;
302                 }
303
304                 ret = 1;
305         } else {
306                 _LOGE("[%s] is not core-tpk.", pkg_path);
307                 ret = -1;
308         }
309
310         __xsystem(delete_argv);
311         return ret;
312 }
313
314 void pkg_native_plugin_on_unload(void)
315 {
316         _LOGD("pkg_native_plugin_on_unload() is called.");
317
318         return;
319 }
320
321 int pkg_plugin_app_is_installed(const char *pkgid)
322 {
323         if (pkgid == NULL) {
324                 _LOGE("pkgid is NULL.");
325                 return LIBRPM_ERROR;
326         }
327
328         _LOGD("pkg_plugin_app_is_installed(%s) is called.", pkgid);
329
330         int ret = -1;
331         ret = _librpm_app_is_installed(pkgid);
332         if (ret == -1) {
333                 _LOGE("_librpm_app_is_installed(%s) failed.", pkgid);
334                 return LIBRPM_ERROR;
335         }
336
337         // 1 for installed, 0 for not installed
338         if (ret == 1) {
339                 _LOGD("pkgid[%s] is installed.", pkgid);
340                 return LIBRPM_SUCCESS;
341         }
342         else {
343                 _LOGD("pkgid[%s] is not installed.", pkgid);
344                 return LIBRPM_ERROR;
345         }
346 }
347
348 int pkg_plugin_get_installed_apps_list(const char *category, const char *option, package_manager_pkg_info_t **list, int *count)
349 {
350         _LOGD("pkg_plugin_get_installed_apps_list() is called.");
351
352         return LIBRPM_SUCCESS;
353 }
354
355 int pkg_plugin_get_app_detail_info(const char *pkgid, package_manager_pkg_detail_info_t *pkg_detail_info)
356 {
357         if (pkgid == NULL || pkg_detail_info == NULL) {
358                 _LOGE("pkgid or pkg_detail_info is NULL.");
359                 return LIBRPM_ERROR;
360         }
361
362         _LOGD("pkg_plugin_get_app_detail_info(%s) is called.", pkgid);
363
364         int ret = 0;
365         char dirname[BUFFSIZE] = {'\0'};
366         long long data_size = 0;
367         char buff[BUFFSIZE] = {'\0'};
368         time_t install_time = 0;
369
370         /* pkgtype is by default rpm */
371         strncpy(pkg_detail_info->pkg_type, "rpm", sizeof(pkg_detail_info->pkg_type));
372
373         /* Get the installed package info from rpm db */
374         ret = _librpm_get_installed_package_info(pkgid, pkg_detail_info);
375         if (ret) {
376                 _LOGE("_librpm_get_installed_package_info(%s) failed.", pkgid);
377                 return LIBRPM_ERROR;
378         }
379
380         /* get data_size */
381         snprintf(dirname, BUFFSIZE-1, "%s/%s/data", USER_APP_FOLDER, pkgid);
382         data_size = _librpm_calculate_dir_size(dirname);
383         if (data_size < 0) {
384                 _LOGE("_librpm_calculate_dir_size(%s) failed.", dirname);
385                 pkg_detail_info->data_size = 0 ;
386         }
387         else {
388                 data_size += BLOCK_SIZE; /* the function does not adds 4096 bytes for the directory size itself*/
389                 pkg_detail_info->data_size = data_size/1024 ;
390         }
391
392         /* Min Platform Version */
393         pkg_detail_info->min_platform_version[0] = '\0';
394
395         /* Optional ID*/
396         pkg_detail_info->optional_id[0] = '\0';
397
398         /* Total Installed Size*/
399         pkg_detail_info->installed_size = pkg_detail_info->app_size + pkg_detail_info->data_size;
400
401         /* Installed Time*/
402         snprintf(buff, BUFFSIZE-1, "db/app-info/%s/installed-time", pkgid);
403         ret = vconf_get_int(buff, (int *)&install_time);
404         if (ret) {
405                 _LOGE("vconf_get_int(%s) failed.", buff);
406                 pkg_detail_info->installed_time = 0;
407         }
408         else
409                 pkg_detail_info->installed_time = install_time;
410
411         return LIBRPM_SUCCESS;
412 }
413
414 int pkg_plugin_get_app_detail_info_from_package(const char *pkg_path, package_manager_pkg_detail_info_t *pkg_detail_info)
415 {
416         if (pkg_path == NULL || pkg_detail_info == NULL) {
417                 _LOGE("pkg_path or pkg_detail_info is NULL.");
418                 return LIBRPM_ERROR;
419         }
420
421         _LOGD("pkg_plugin_get_app_detail_info_from_package(%s) is called.", pkg_path);
422
423         int ret = 0;
424         long long data_size = 0;
425         char *str = NULL;
426         char dirname[BUFFSIZE] = {'\0'};
427         char buff[BUFFSIZE] = {'\0'};
428         time_t install_time = 0;
429
430         if (__is_core_tpk_app(pkg_path, pkg_detail_info) == 1) {
431                 return LIBRPM_SUCCESS;
432         }
433
434         /* populate pkg type */
435         str = strrchr(pkg_path, 46);    /* 46 is ASCII for . */
436         strncpy(pkg_detail_info->pkg_type, (str + 1), strlen(str + 1));
437
438         /* populate rpm header specific info (name, version, description, size)*/
439         ret = _librpm_get_package_header_info(pkg_path, pkg_detail_info);
440         if (ret) {
441                 return LIBRPM_ERROR;
442         }
443
444         /*get data_size. If pkg is not installed it will be 0*/
445         snprintf(dirname, BUFFSIZE-1, "%s/%s/data",
446                                 USER_APP_FOLDER, pkg_detail_info->pkgid);
447
448         data_size = _librpm_calculate_dir_size(dirname);
449         if (data_size < 0) {
450                 _LOGE(
451                                 "Calculate dir size failed\n");
452                 pkg_detail_info->data_size = 0 ;
453         }
454         else {
455                 data_size += BLOCK_SIZE; /* the function does not adds 4096
456                                         bytes for the directory size itself*/
457
458                 pkg_detail_info->data_size = data_size/1024 ;
459         }
460
461         /* Min Platform Version */
462         pkg_detail_info->min_platform_version[0] = '\0';
463
464         /* Optional ID*/
465         pkg_detail_info->optional_id[0] = '\0';
466
467         /* Total Installed Size*/
468         pkg_detail_info->installed_size = pkg_detail_info->app_size +
469                                                                         pkg_detail_info->data_size;
470
471         /* Installed Time */
472         snprintf(buff, 256, "db/app-info/%s/installed-time", pkg_detail_info->pkgid);
473         ret = vconf_get_int(buff, (int *)&install_time);
474         if (ret) {
475                 _LOGE("get installed time failed\n");
476                 pkg_detail_info->installed_time = 0;
477         }
478         else
479                 pkg_detail_info->installed_time = install_time;
480
481
482         return LIBRPM_SUCCESS;
483 }
484
485 API int pkg_plugin_on_load(pkg_plugin_set *set)
486 {
487         if (set == NULL) {
488                 _LOGE("set is NULL.");
489                 return LIBRPM_ERROR;
490         }
491
492         _LOGD("pkg_plugin_on_load() is called.");
493
494         static int initialized = 0;
495         rpmRC rc;
496         memset(set, 0x00, sizeof(pkg_plugin_set));
497
498         if (!initialized) {
499                 rc = rpmReadConfigFiles(NULL, NULL);
500                 if (rc == RPMRC_OK) {
501                         initialized = 1;
502                         _LOGD("rpmReadConfigFiles() is ok.");
503                 }
504                 else {
505                         _LOGE("rpmReadConfigFiles() failed.");
506                         initialized = 0;
507                         return LIBRPM_ERROR;
508                 }
509         }
510
511         set->plugin_on_unload = pkg_native_plugin_on_unload;
512         set->pkg_is_installed = pkg_plugin_app_is_installed;
513         set->get_installed_pkg_list = pkg_plugin_get_installed_apps_list;
514         set->get_pkg_detail_info = pkg_plugin_get_app_detail_info;
515         set->get_pkg_detail_info_from_package = pkg_plugin_get_app_detail_info_from_package;
516
517         return LIBRPM_SUCCESS;
518 }