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