Update source from tizen 2.3
[platform/core/base/rpm-installer.git] / backend / src / rpm / rpm-installer-core.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 /* System Include files */
24 #include <stdbool.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <sys/wait.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #include <wait.h>
35 #include <regex.h>
36 #include <pthread.h>
37 #include <dirent.h>
38 #include <fcntl.h>
39 #include <errno.h>
40
41 /* SLP include files */
42 #include <pkgmgr-info.h>
43 #include <pkgmgr_parser.h>
44 #include "rpm-installer.h"
45 #include "rpm-installer-type.h"
46 #include "rpm-installer-util.h"
47 #include "db-util.h"
48 #include "rpm-frontend.h"
49
50
51 extern char *gpkgname;
52 extern int do_upgrade;
53
54 char* _rpm_load_directory(char *directory,char* pkgfile)
55 {
56         DIR *dir;
57         struct dirent entry, *result;
58         int ret;
59         char *buf = NULL;
60         char *pkgname = NULL;
61 //      char *rpm_pkgname = NULL;
62         char xml_file[PATH_MAX] = {0};
63
64         buf = malloc(BUF_SIZE);
65         if (buf == NULL) {
66                 _LOGE("malloc failed.\n");
67                 return NULL;
68         }
69
70         dir = opendir(directory);
71         if (!dir) {
72                 if (strerror_r(errno, buf, BUF_SIZE) == 0)
73                 _LOGE("Can not access to the [%s] because %s.\n", directory, buf);
74                 free(buf);
75                 return NULL;
76         }
77
78         _LOGD("Loading manifest files from %s\n", directory);
79
80         for (ret = readdir_r(dir, &entry, &result);
81                         ret == 0 && result != NULL;
82                         ret = readdir_r(dir, &entry, &result)) {
83                 char *manifest = NULL;
84
85                 if (!strcmp(entry.d_name, ".") ||
86                         !strcmp(entry.d_name, "..")) {
87                         continue;
88                 }
89
90                 manifest = _manifest_to_package(entry.d_name);
91                 if (!manifest) {
92                         _LOGE("Failed to convert file to xml[%s].\n", entry.d_name);
93                         continue;
94                 }
95
96                 memset(xml_file, '\0', PATH_MAX);
97                 snprintf(xml_file,PATH_MAX-1,"%s/%s",directory,manifest);
98                 _LOGD("manifest is [%s] and its full path is [%s]",manifest,xml_file);
99                 ret = _get_package_name_from_xml(xml_file,&pkgname);
100                 if(ret != PMINFO_R_OK || pkgname == NULL){
101                         _LOGE("Unable To read [%s] manifest file",xml_file);
102                         free(manifest);
103                         continue;
104                 }
105
106                 else
107                 {
108                         snprintf(buf, BUF_SIZE, "%s/%s", directory, manifest);
109                         _LOGD("Manifest file is %s\n",manifest);
110                         free(manifest);
111                         break;
112                 }
113
114 #if 0   //dont check pkgname from rpm-name, there is a bug
115                 ret = _get_pkgname_from_rpm_name(pkgfile, &rpm_pkgname);
116                 if(ret != RPM_INSTALLER_SUCCESS || rpm_pkgname == NULL){
117                         _LOGE("Couldn't get the pkgname from rpm file [%s]",pkgfile);
118                         if(pkgname){
119                                 free(pkgname);
120                                 pkgname = NULL;
121                         }
122                         if(buf){
123                                 free(buf);
124                                 buf = NULL;
125                         }
126                         closedir(dir);
127                         free(manifest);
128                         return NULL;
129                 }
130                 _LOGD("Pkgname from xml is [%s] and pkgname from rpm's name is [%s]",pkgname,rpm_pkgname);
131
132                 /*
133                 Compare the package name which is extracted from manifest file with package name which is extracted from rpm file's name.
134                 If match is successful then it is required manifest file.
135                 */
136
137                 if(!strcmp(pkgname,rpm_pkgname)){
138                         snprintf(buf, BUF_SIZE, "%s/%s", directory, manifest);
139                         _LOGD("Manifest file is %s\n",buf);
140                         free(manifest);
141                         break;
142                 }else{
143                         free(manifest);
144                         if(pkgname){
145                                 free(pkgname);
146                                 pkgname = NULL;
147                         }
148                         if(rpm_pkgname){
149                                 free(rpm_pkgname);
150                                 rpm_pkgname = NULL;
151                         }
152                 }
153 #endif
154         }
155
156         closedir(dir);
157
158         if(pkgname){
159                 free(pkgname);
160                 pkgname = NULL;
161         }
162 #if 0
163         if(rpm_pkgname){
164                 free(rpm_pkgname);
165                 rpm_pkgname = NULL;
166         }
167 #endif
168
169         return buf;
170 }
171
172 pkginfo *_rpm_installer_get_pkgfile_info(char *pkgfile)
173 {
174         pkginfo *info = NULL;
175         manifest_x *mfx = NULL;
176         int ret = 0;
177         int m_exist = 0;
178         char cwd[BUF_SIZE] = {'\0'};
179         char buff[BUF_SIZE] = {'\0'};
180         char manifest[BUF_SIZE] = { '\0'};
181         char *temp = NULL;
182
183         temp = getcwd(cwd, BUF_SIZE);
184         if ((temp == NULL) || (cwd[0] == '\0')) {
185                 _LOGE("getcwd() failed.\n");
186                 return NULL;
187         }
188
189         ret = mkdir(TEMP_DIR, 0644);
190         if (ret < 0) {
191                 if (access(TEMP_DIR, F_OK) == 0) {
192                         _rpm_delete_dir(TEMP_DIR);
193                         ret = mkdir(TEMP_DIR, 0644);
194                         if (ret < 0) {
195                                 _LOGE("mkdir() failed.\n");
196                                 return NULL;
197                         }
198                 } else {
199                         _LOGE("mkdir() failed.\n");
200                         return NULL;
201                 }
202         }
203
204         ret = chdir(TEMP_DIR);
205         if (ret != 0) {
206                 _LOGE("chdir(%s) failed [%s].\n", TEMP_DIR, strerror(errno));
207                 goto err;
208         }
209
210         _LOGD("switched to %s\n", TEMP_DIR);
211
212         const char *cpio_argv[] = { CPIO_SCRIPT, pkgfile, NULL };
213         ret = _ri_xsystem(cpio_argv);
214
215         snprintf(manifest, BUF_SIZE, "%s/opt/share/packages", TEMP_DIR);
216         char* manifestpath = _rpm_load_directory(manifest,pkgfile);
217         if (manifestpath != NULL) {
218                 strncpy(buff, manifestpath, sizeof(buff) - 1);
219                 free(manifestpath);
220         }
221
222         if (buff[0] == '\0') {
223                 snprintf(manifest, BUF_SIZE, "%s/usr/share/packages", TEMP_DIR);
224                 manifestpath = _rpm_load_directory(manifest,pkgfile);
225                 if (manifestpath != NULL) {
226                         strncpy(buff, manifestpath, sizeof(buff) - 1);
227                         free(manifestpath);
228                 }
229
230                 if (buff[0] == '\0') {
231                         goto err;
232                 } else {
233                         m_exist = 1;
234                 }
235         } else {
236                 m_exist = 1;
237         }
238
239         _LOGD("Manifest file is [%s]",buff);
240
241         if (m_exist) {
242
243                 _LOGD("The path of manifest.xml is %s.\n", buff);
244
245                 /*get package name from xml*/
246                 mfx = pkgmgr_parser_process_manifest_xml(buff);
247                 if (mfx != NULL) {
248
249                         info = calloc(1, sizeof(pkginfo));
250                         if (info == NULL) {
251                                 _LOGE("calloc failed.\n");
252                                 goto err;
253                         }
254
255                         strncpy(info->package_name, mfx->package, sizeof(info->package_name) - 1);
256                         strncpy(info->version, mfx->version, sizeof(info->version) - 1);
257                         _LOGD("_rpm_installer_get_pkgfile_info, pkgname: (%s), version(%s)\n", info->package_name, info->version);
258                 }
259         }
260
261 err:
262         _rpm_delete_dir(TEMP_DIR);
263
264         ret = chdir(cwd);
265         if (ret != 0) {
266                 _LOGE("chdir(%s) failed [%s].\n", cwd, strerror(errno));
267         }
268
269         if (mfx != NULL) {
270                 pkgmgr_parser_free_manifest_xml(mfx);
271         }
272
273         return info;
274 }
275
276 pkginfo *_rpm_installer_get_pkgname_info(const char *pkgid)
277 {
278         pkginfo *info = NULL;
279         int ret = 0;
280         char *packageid = NULL;
281         char *version = NULL;
282         pkgmgrinfo_pkginfo_h handle = NULL;
283
284         if (pkgid == NULL) {
285                 _LOGE("pkgid is NULL.\n");
286                 return NULL;
287         }
288
289         info = malloc(sizeof(pkginfo));
290         if (info == NULL) {
291                 _LOGE("malloc failed.\n");
292                 return NULL;
293         }
294
295         ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgid, &handle);
296         if (ret != PMINFO_R_OK || handle == NULL) {
297                 _LOGE("fisrt installation, pkgid=[%s]", pkgid);
298                 free(info);
299                 return NULL;
300         }
301
302         ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &packageid);
303         if (ret != PMINFO_R_OK) {
304                 _LOGE("failed to get the pkgid.\n");
305                 goto err;
306         }
307         strncpy(info->package_name, packageid, sizeof(info->package_name) - 1);
308
309         ret = pkgmgrinfo_pkginfo_get_version(handle, &version);
310         if (ret != PMINFO_R_OK) {
311                 _LOGE("failed to get the version.\n");
312                 goto err;
313         }
314         strncpy(info->version, version, sizeof(info->version) - 1);
315
316         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
317
318         _LOGD("pkgid=[%s], version=[%s]", info->package_name, info->version);
319
320         return info;
321
322 err:
323         if(info){
324                 free(info);
325                 info = NULL;
326         }
327         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
328         return NULL;
329 }
330
331 int _rpm_installer_corexml_install(char *pkgfilepath)
332 {
333         /* Get package ID from filepath <pkgid.xml>*/
334         char *p = NULL;
335         char *q = NULL;
336         char *temp = NULL;
337         int ret = 0;
338         int idx = 0;
339         temp = strdup(pkgfilepath);
340         if (temp == NULL)
341                 return RPM_INSTALLER_ERR_NOT_ENOUGH_MEMORY;
342         p = strrchr(temp, '/');
343         if (p) {
344                 p++;
345         } else {
346                 free(temp);
347                 return RPM_INSTALLER_ERR_INTERNAL;
348         }
349         /*p now points to pkgid.xml*/
350         q = strrchr(p, '.');
351         if (q == NULL) {
352                 _LOGE("Failed to extract pkgid from xml name\n");
353                 free(temp);
354                 return RPM_INSTALLER_ERR_INTERNAL;
355         }
356         idx = strlen(p) - strlen(q);
357         p[idx] = '\0';
358         _LOGD("package id is [%s]", p);
359         ret = _rpm_install_corexml(pkgfilepath, p);
360         free(temp);
361         return ret;
362 }
363
364 int _rpm_installer_package_install(char *pkgfilepath, bool forceinstall,
365                                    char *installoptions, char *clientid)
366 {
367         int err = 0;
368         char *p = NULL;
369         if (forceinstall == true && installoptions == NULL)
370                 return RPM_INSTALLER_ERR_WRONG_PARAM;
371
372         /* Check for core xml installation */
373         p = strrchr(pkgfilepath, '.');
374         if (p) {
375                 if (strncmp(p+1, "xml", 3) == 0) {
376                         err = _rpm_installer_corexml_install(pkgfilepath);
377                         if (err) {
378                                 _LOGE("_rpm_installer_corexml_install() failed\n");
379                         } else {
380                                 _LOGE("_rpm_installer_corexml_install() success\n");
381                         }
382                         return err;
383                 }
384         } else {
385                 _LOGE("pkgfilepath does not have an extension\n");
386                 return RPM_INSTALLER_ERR_INTERNAL;
387         }
388         /* rpm installation */
389         pkginfo *info = NULL;
390         pkginfo *tmpinfo = NULL;
391         /*Check to see if the package is already installed or not
392            If it is installed, compare the versions. If the current version
393            is higher than the installed version, upgrade it automatically
394            else ask for user confirmation before downgrading */
395
396         info = _rpm_installer_get_pkgfile_info(pkgfilepath);
397         if (info == NULL) {
398                 /* failed to get pkg info */
399                 return RPM_INSTALLER_ERR_INTERNAL;
400         }
401
402         _ri_set_backend_state_info(GOT_PACKAGE_INFO_SUCCESSFULLY);
403         _ri_save_last_input_info(pkgfilepath,INSTALL_CMD,0);
404         if (gpkgname) {
405                 free(gpkgname);
406                 gpkgname = NULL;
407         }
408         gpkgname = strdup(info->package_name);
409         if(gpkgname == NULL){
410                 _LOGE("Malloc failed!!");
411                 if(info){
412                         free(info);
413                         info = NULL;
414                 }
415                 return RPM_INSTALLER_ERR_INTERNAL;
416         }
417
418         tmpinfo = _rpm_installer_get_pkgname_info(info->package_name);
419         if (tmpinfo == NULL) {
420                 _LOGD("tmpinfo is null.\n");
421
422                 /* package is not installed. Go for installation. */
423                 if (info) {
424                         free(info);
425                         info = NULL;
426                 }
427
428                 err = _rpm_install_pkg_with_dbpath(pkgfilepath, gpkgname, clientid);
429                 if (err != 0) {
430                         _LOGE(
431                                "install complete with error(%d)\n", err);
432                         return err;
433                 } else {
434                         _ri_set_backend_state_info(REQUEST_COMPLETED);
435                         return RPM_INSTALLER_SUCCESS;
436                 }
437         } else if (strcmp(info->version, tmpinfo->version) > 0) {
438                 /*upgrade */
439
440                 _LOGD("[upgrade] %s, %s\n", info->version, tmpinfo->version);
441
442                 err = _rpm_upgrade_pkg_with_dbpath(pkgfilepath, gpkgname);
443                 if (err != 0) {
444                         _LOGE(
445                                "upgrade complete with error(%d)\n", err);
446                         if (info) {
447                                 free(info);
448                                 info = NULL;
449                         }
450                         if (tmpinfo) {
451                                 free(tmpinfo);
452                                 tmpinfo = NULL;
453                         }
454                         return err;
455                 } else {
456                         _ri_set_backend_state_info(REQUEST_COMPLETED);
457                         if (info) {
458                                 free(info);
459                                 info = NULL;
460                         }
461                         if (tmpinfo) {
462                                 free(tmpinfo);
463                                 tmpinfo = NULL;
464                         }
465                         return RPM_INSTALLER_SUCCESS;
466                 }
467         } else if (strcmp(info->version, tmpinfo->version) < 0) {
468
469                 _LOGD("[down grade] %s, %s\n", info->version, tmpinfo->version);
470
471                         err = _rpm_upgrade_pkg_with_dbpath(pkgfilepath, gpkgname);
472                         if (err != 0) {
473                                 _LOGE(
474                                        "upgrade complete with error(%d)\n",
475                                        err);
476                                 if (info) {
477                                         free(info);
478                                         info = NULL;
479                                 }
480                                 if (tmpinfo) {
481                                         free(tmpinfo);
482                                         tmpinfo = NULL;
483                                 }
484                                 return err;
485                         }else{
486                         _ri_set_backend_state_info(REQUEST_COMPLETED);
487                         if (info) {
488                                 free(info);
489                                 info = NULL;
490                         }
491                         if (tmpinfo) {
492                                 free(tmpinfo);
493                                 tmpinfo = NULL;
494                         }
495                         return RPM_INSTALLER_SUCCESS;
496
497                 }
498
499         } else {
500                 /*same package. Reinstall it. Manifest should be parsed again */
501
502                 _LOGD("[same pkg] %s, %s\n", info->package_name, info->version);
503
504                 err = _rpm_upgrade_pkg_with_dbpath(pkgfilepath, gpkgname);
505                 if (err != 0) {
506                         _LOGE(
507                                "upgrade complete with error(%d)\n", err);
508                         if (info) {
509                                 free(info);
510                                 info = NULL;
511                         }
512                         if (tmpinfo) {
513                                 free(tmpinfo);
514                                 tmpinfo = NULL;
515                         }
516                         return err;
517                 } else {
518                         _ri_set_backend_state_info(REQUEST_COMPLETED);
519                         if (info) {
520                                 free(info);
521                                 info = NULL;
522                         }
523                         if (tmpinfo) {
524                                 free(tmpinfo);
525                                 tmpinfo = NULL;
526                         }
527                         return RPM_INSTALLER_SUCCESS;
528                 }
529         }
530
531         return RPM_INSTALLER_SUCCESS;
532
533 }
534
535 int _rpm_installer_package_install_with_dbpath(char *pkgfilepath, char *clientid)
536 {
537         int ret = 0;
538         pkginfo *info = NULL;
539         pkginfo *tmpinfo = NULL;
540
541         /*Check to see if the package is already installed or not
542            If it is installed, compare the versions. If the current version
543            is higher than the installed version, upgrade it automatically
544            else ask for user confirmation before downgrading */
545
546         _LOGD("[##]start : _rpm_installer_package_install_with_dbpath\n");
547
548         info = _rpm_installer_get_pkgfile_info(pkgfilepath);
549         if (info == NULL) {
550                 _LOGE("@Failed to get pkg info.\n");
551                 /* failed to get pkg info */
552                 return RPM_INSTALLER_ERR_INTERNAL;
553         }
554
555         _ri_set_backend_state_info(GOT_PACKAGE_INFO_SUCCESSFULLY);
556         _ri_save_last_input_info(info->package_name,EFLWGT_INSTALL_CMD,0);
557         if (gpkgname) {
558                 free(gpkgname);
559                 gpkgname = NULL;
560         }
561         gpkgname = strdup(info->package_name);
562         if(gpkgname == NULL){
563                 _LOGE("Malloc failed!!");
564                 if(info){
565                         free(info);
566                         info = NULL;
567                 }
568                 return RPM_INSTALLER_ERR_INTERNAL;
569         }
570
571         tmpinfo = _rpm_installer_get_pkgname_info(info->package_name);
572         if (tmpinfo == NULL) {
573                 /* package is not installed. Go for installation. */
574                 _LOGD("#package is not installed. Go for installation\n");
575                 ret = _rpm_install_pkg_with_dbpath(pkgfilepath, info->package_name, clientid);
576
577         } else if (strcmp(info->version, tmpinfo->version) > 0) {
578                 /*upgrade */
579                 _LOGD("#package is installed. Go for upgrade\n");
580                 ret = _rpm_upgrade_pkg_with_dbpath(pkgfilepath, info->package_name);
581         } else if (strcmp(info->version, tmpinfo->version) < 0) {
582                 /*downgrade */
583                 _LOGD("#package is installed. Go for upgrade\n");
584                 ret = _rpm_upgrade_pkg_with_dbpath(pkgfilepath, info->package_name);
585
586         } else {
587                 /*same package. Reinstall it. Manifest should be parsed again */
588                 _LOGD( "#package is same. Go for reinstall(upgrade)\n");
589                 ret = _rpm_upgrade_pkg_with_dbpath(pkgfilepath, info->package_name);
590         }
591
592         if (info) {
593                 free(info);
594                 info = NULL;
595         }
596         if (tmpinfo) {
597                 free(tmpinfo);
598                 tmpinfo = NULL;
599         }
600
601         if (ret != 0) {
602                 _LOGE("[@@]end : _rpm_installer_package_install_with_dbpath(%d)\n", ret);
603         } else {
604                 _LOGD( "[##]end : _rpm_installer_package_install_with_dbpath \n");
605         }
606
607         return ret;
608 }
609
610 int _rpm_installer_package_uninstall_with_dbpath(const char *pkgid)
611 {
612         return _rpm_uninstall_pkg_with_dbpath(pkgid, 0);
613 }
614
615 int _rpm_installer_package_uninstall(char *pkgid)
616 {
617         int ret = 0;
618
619         _LOGD( "start : _rpm_installer_package_uninstall\n");
620
621         pkginfo *tmppkginfo = _rpm_installer_get_pkgname_info(pkgid);
622         if (tmppkginfo == NULL) {
623                 _LOGE("tmppkginfo is NULL.\n");
624                 return RPM_INSTALLER_ERR_PACKAGE_NOT_INSTALLED;
625         }
626         if (tmppkginfo) {
627                 free(tmppkginfo);
628                 tmppkginfo = NULL;
629         }
630 #ifndef SEND_PKGPATH
631         if (gpkgname) {
632                 free(gpkgname);
633                 gpkgname = NULL;
634         }
635
636         gpkgname = strdup(pkgid);
637 //      _ri_broadcast_status_notification(pkgid, "command", "Uninstall");
638 #endif
639         _ri_set_backend_state_info(GOT_PACKAGE_INFO_SUCCESSFULLY);
640         _ri_save_last_input_info(pkgid,DELETE_CMD,0);
641         ret = _rpm_uninstall_pkg(pkgid);
642
643         _ri_set_backend_state_info(REQUEST_COMPLETED);
644
645         _LOGD("end : _rpm_installer_package_uninstall(%d)\n", ret);
646
647         return ret;
648 }
649
650 int _rpm_installer_clear_private_data(char *pkgid)
651 {
652         if (pkgid == NULL)
653                 return RPM_INSTALLER_ERR_WRONG_PARAM;
654         char dir_path[BUF_SIZE] = { '\0' };
655         int ret = -1;
656         snprintf(dir_path, 255, "/opt/usr/apps/%s/data/", pkgid);
657         ret = _ri_recursive_delete_dir(dir_path);
658         return ret;
659 }