upload tizen1.0 source
[pkgs/n/native-installer.git] / backend / src / core / nativeinstallercore.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
26
27 /* System Include files */
28 #include <stdbool.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <sys/wait.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <sys/stat.h>
37 #include <dirent.h>
38 #include <unistd.h>
39 #include <wait.h>
40 #include <regex.h>
41
42 /* SLP include files */
43 #include "nativeinstaller.h"
44 #include "native_installer_util.h"
45 #include "db-util.h"
46
47 #define EXTRACT_MENIFEST        "/usr/bin/extract_manifest.sh"
48 #define FIND_PACKAGE            "/usr/bin/find_package.sh"
49 #define MANIFEST_FILE_NAME "control"
50
51 typedef struct _pkgfile_info {
52         char *ppkg_filename;
53         char *ppkgtype;
54         char pkg_manifest_filepath[256];
55         char extracted_pkg_location[256];
56
57 } pkgfile_info;
58
59
60 extern char *gptrpkgname;
61 extern int do_upgrade;
62 extern int quiet;
63 static int __pkgmgr_get_filename(char *package_filepath, 
64                                  pkgfile_info *ppkg_fileinfo);
65 static int __recursive_delete_dir(char *dirname);
66
67 pkginfo *_pkgmgr_get_installed_pkg_info(char *pkgname)
68 {
69         char pkg_manifest_filepath[256];
70         pkginfo *info = NULL;
71         int err;
72         const char *argv[] = { FIND_PACKAGE, pkgname, NULL };
73
74         if (pkgname == NULL)
75                 return NULL;
76
77         err = _xsystem(argv);
78         d_msg_backend(DEBUG_INFO,
79                       "[_pkgmgr_get_installed_pkg_info] _xsystem returns %d\n",
80                          err);
81         if (err == 1) {
82                 d_msg_backend(DEBUG_INFO,
83                               "[_pkgmgr_get_installed_pkg_info] "
84                                 "Package Not installed \n");
85         } else if (err == 2) {
86                 d_msg_backend(DEBUG_INFO,
87                               "[_pkgmgr_get_installed_pkg_info] "
88                                 "package already install\n");
89                 snprintf(pkg_manifest_filepath, 255, "/var/pkgmgr/%s/pkginfo",
90                         pkgname);
91                 d_msg_backend(DEBUG_INFO, "manifest=%s\n",
92                               pkg_manifest_filepath);
93                 info =
94                     _pkgmgr_txt_parser_read_manifest(
95                                         (char *)(pkg_manifest_filepath));
96
97                 if (info == NULL) {
98                         d_msg_backend(DEBUG_ERR,
99                                       "Failed to parse Manifest file \n");
100                         info = NULL;
101                 }
102
103         } else {
104                 d_msg_backend(DEBUG_ERR,
105                               "[_pkgmgr_get_installed_pkg_info] "
106                                 "_xsystem returns error = %d\n",
107                                 err);
108         }
109         return info;
110
111 }
112
113 static int __recursive_delete_dir(char *dirname)
114 {
115         DIR *dp;
116         struct dirent *ep;
117         char abs_filename[FILENAME_MAX];
118         struct stat stFileInfo;
119         dp = opendir(dirname);
120         if (dp != NULL) {
121                 while (ep = readdir(dp)) {
122                         snprintf(abs_filename, FILENAME_MAX, "%s/%s", dirname,
123                                  ep->d_name);
124                         if (lstat(abs_filename, &stFileInfo) < 0)
125                                 perror(abs_filename);
126                         if (S_ISDIR(stFileInfo.st_mode)) {
127                                 if (strcmp(ep->d_name, ".") &&
128                                     strcmp(ep->d_name, "..")) {
129                                         __recursive_delete_dir(abs_filename);
130                                         remove(abs_filename);
131                                 }
132                         } else {
133                                 remove(abs_filename);
134                         }
135                 }
136                 (void)closedir(dp);
137         } else {
138                 d_msg_backend(DEBUG_ERR,"Couldn't open the directory\n");
139                 return NATIVEINSTALLER_ERR_CLEAR_DATA_FAILED;
140         }
141
142         return NATIVEINSTALLER_SUCCESS;
143 }
144
145 static int __pkgmgr_get_filename(char *package_filepath, 
146                                  pkgfile_info *ppkg_fileinfo)
147 {
148         regex_t re;
149         regmatch_t mached[5];
150         int ret = 0;
151         char *ptr = NULL;
152         ret =
153             regcomp(&re, "[/]*([.a-z_A-Z0-9-]+\\.([aA][pP][kK]|[dD][eE][bB]))",
154                     REG_EXTENDED);
155         if (ret != 0) {
156                 d_msg_backend(DEBUG_ERR,
157                               "[__pkgmgr_get_filename]regcomp failed(%d)\n",
158                                         ret);
159                 return -1;
160         }
161         ret = regexec(&re, package_filepath, 5, mached, 0);
162         if (ret != 0) {
163                 d_msg_backend(DEBUG_ERR,
164                               "[__pkgmgr_get_filename]regexec failed(%s)(%d)\n",
165                               package_filepath, ret);
166                 regfree(&re);
167                 return -1;
168         }
169         /*Use simple logic to extract filename 
170         as it may contain any character */
171         ptr = strrchr(package_filepath, 47);    /* 47 is ASCII for / */
172         if (!ptr)
173                 return -1;
174         if (ptr + 1)
175                 ppkg_fileinfo->ppkg_filename = strdup(ptr + 1);
176         ppkg_fileinfo->ppkgtype =
177             _substring(package_filepath, mached[2].rm_so,
178                       mached[2].rm_eo - mached[2].rm_so);
179
180         d_msg_backend(DEBUG_INFO,
181                       "[getPackageFileName][%s] -> [%s]; pkgtype = %s \n",
182                       package_filepath, ppkg_fileinfo->ppkg_filename,
183                       ppkg_fileinfo->ppkgtype);
184         regfree(&re);
185         return 1;
186 }
187
188 pkginfo *_pkgmgr_get_pkg_info(char *pkg_filepath, int *errno,
189                               bool *alreay_installed)
190 {
191         pkgfile_info pkg_fileinfo;
192         pkginfo *info = NULL;
193         pkginfo *tmpinfo = NULL;
194         int err = 0;
195         const char *argv[] = { EXTRACT_MENIFEST, pkg_filepath, NULL };
196
197         if (pkg_filepath == NULL || errno == NULL || alreay_installed == NULL)
198                 return NULL;
199
200         *errno = 0;
201         err = _xsystem(argv);
202         d_msg_backend(DEBUG_INFO, "[_pkgmgr_get_pkg_info] "
203         "_xsystem returns %d\n", err);
204         if (err != 0) {
205                 d_msg_backend(DEBUG_ERR,
206                               "[_pkgmgr_get_pkg_info] _xsystem returns %d\n", 
207                                 err);
208                 /*E_WRONG_ARGS=5 */
209                 /*E_FILE_NOT_FOUND=6 */
210                 /*E_NO_MANIFEST=7 */
211                 /*E_NOT_VALID_ARCHIVE=8 */
212
213                 switch (err) {
214                 case 6:
215                         *errno = NATIVEINSTALLER_ERR_PKG_NOT_FOUND;
216                         break;
217                 case 7:
218                         *errno = NATIVEINSTALLER_ERR_NO_MANIFEST;
219                         break;
220                 case 8:
221                         *errno = NATIVEINSTALLER_ERR_NO_DEB_FILE;
222                         break;
223                 default:
224                         *errno = NATIVEINSTALLER_ERR_UNKNOWN;
225                         break;
226                 }
227                 return NULL;
228         }
229
230         err = __pkgmgr_get_filename(pkg_filepath, &pkg_fileinfo);
231         if (err == -1) {
232                 *errno = NATIVEINSTALLER_ERR_UNKNOWN;
233                 return NULL;
234         }
235
236         if (pkg_fileinfo.ppkgtype == NULL) {
237                 d_msg_backend(DEBUG_ERR, "Package type is returned NULL \n");
238                 return NULL;
239         }
240
241         if (strcmp(pkg_fileinfo.ppkgtype, PKGTYPE) != 0) {
242                 d_msg_backend(DEBUG_ERR,
243                               "Package file is not a debian file \n");
244                 *errno = NATIVEINSTALLER_ERR_NO_DEB_FILE;
245                 return NULL;
246         }
247         snprintf(pkg_fileinfo.extracted_pkg_location, 255, "/var/pkgmgr/%s",
248                 pkg_fileinfo.ppkg_filename);
249
250         snprintf(pkg_fileinfo.pkg_manifest_filepath, 255, 
251                  "/var/pkgmgr/%s/metainfo/%s",
252                 pkg_fileinfo.ppkg_filename, MANIFEST_FILE_NAME);
253         d_msg_backend(DEBUG_INFO, "manifest=%s\n",
254                       pkg_fileinfo.pkg_manifest_filepath);
255         info = _pkgmgr_txt_parser_read_manifest(
256                                 (char *)(pkg_fileinfo.pkg_manifest_filepath));
257
258         if (info == NULL) {
259                 d_msg_backend(DEBUG_ERR, "Failed to parse Manifest file \n");
260                 *errno = NATIVEINSTALLER_ERR_UNKNOWN;
261                 return NULL;
262         }
263         unlink(pkg_fileinfo.pkg_manifest_filepath);
264         if (pkg_fileinfo.ppkg_filename) {
265                 free(pkg_fileinfo.ppkg_filename);
266                 pkg_fileinfo.ppkg_filename = NULL;
267         }
268         if (pkg_fileinfo.ppkgtype) {
269                 free(pkg_fileinfo.ppkgtype);
270                 pkg_fileinfo.ppkgtype = NULL;
271         }
272
273         /* check is it already installed or not */
274         tmpinfo = _pkgmgr_get_installed_pkg_info(info->package_name);
275         if (tmpinfo != NULL) {
276                 /*already installed */
277                 *alreay_installed = true;
278                 free(tmpinfo);
279                 tmpinfo = NULL;
280         }
281
282         return info;
283 }
284
285 int _pkgmgr_package_install(char *pkgfilepath, bool forceinstall,
286                             char *installoptions)
287 {
288         int err = 0;
289         pkginfo *info = NULL;
290         pkginfo *tmpinfo = NULL;
291         bool alreadyinstalled = false;
292         if (forceinstall == true && installoptions == NULL)
293                 return NATIVEINSTALLER_ERR_WRONG_PARAM;
294
295         info = _pkgmgr_get_pkg_info(pkgfilepath, &err, &alreadyinstalled);
296         if (err != 0 || info == NULL) {
297                 if (info != NULL)
298                         free(info);
299                 return err;
300         }
301 #ifndef SEND_PKGPATH
302         gptrpkgname = strdup(info->package_name);
303         _broadcast_status_notification(info->package_name, "start", "install");
304         _broadcast_status_notification(info->package_name, 
305                                        "command", "Install");
306 #endif
307
308         if (alreadyinstalled == true && forceinstall != true) {
309                 tmpinfo = _pkgmgr_get_installed_pkg_info(info->package_name);
310                 if (tmpinfo == NULL)
311                         return NATIVEINSTALLER_ERR_PACKAGE_NOT_INSTALLED;
312
313                 d_msg_backend(DEBUG_ERR,
314                               "installed version is %s and to be "
315                                 "installed version is %s\n",
316                               tmpinfo->version, info->version);
317                 if (strcmp(info->version, tmpinfo->version) == 0) {
318                         _set_backend_state_info(GOT_PACKAGE_INFO_SUCCESSFULLY);
319                         err = _pkgmgr_dpkg_upgrade_pkg(pkgfilepath,
320                                                  installoptions);
321                         if (err != 0) {
322                                 d_msg_backend(DEBUG_ERR,
323                                       "upgrade complete with error(%d)\n",
324                                               err);
325                                 if (info) {
326                                         free(info);
327                                         info = NULL;
328                                 }
329                                 if (tmpinfo) {
330                                         free(tmpinfo);
331                                         tmpinfo = NULL;
332                                 }
333                                 return err;
334                         }
335                         _set_backend_state_info(DPKG_REQUEST_COMPLETED);
336                         if (info) {
337                                 free(info);
338                                 info = NULL;
339                         }
340                         if (tmpinfo) {
341                                 free(tmpinfo);
342                                 tmpinfo = NULL;
343                         }
344                         return NATIVEINSTALLER_SUCCESS;
345                 } else if (strcmp(info->version, tmpinfo->version) > 0) {
346                         /*upgrade */
347                         _set_backend_state_info(GOT_PACKAGE_INFO_SUCCESSFULLY);
348                         err = _pkgmgr_dpkg_upgrade_pkg(
349                                                 pkgfilepath, installoptions);
350                         if (err != 0) {
351                                 d_msg_backend(DEBUG_ERR,
352                                               "upgrade complete with error(%d)\n",
353                                               err);
354                                 if (info) {
355                                         free(info);
356                                         info = NULL;
357                                 }
358                                 if (tmpinfo) {
359                                         free(tmpinfo);
360                                         tmpinfo = NULL;
361                                 }
362                                 return err;
363                         }
364                         _set_backend_state_info(DPKG_REQUEST_COMPLETED);
365                         if (info) {
366                                 free(info);
367                                 info = NULL;
368                         }
369                         if (tmpinfo) {
370                                 free(tmpinfo);
371                                 tmpinfo = NULL;
372                         }
373                         return NATIVEINSTALLER_SUCCESS;
374
375                 } else if (strcmp(info->version, tmpinfo->version) < 0) {
376                         /*show popup and confirm from user if non quiet mode
377                         else continue downgrade*/
378                         if (quiet == 1) {
379                                 do_upgrade = 1;
380                         }
381                         switch (do_upgrade) {
382                         case -1:
383                                         _set_backend_state_info(DPKG_REQUEST_PENDING);
384                                         if (info) {
385                                                 free(info);
386                                                 info = NULL;
387                                         }
388                                         if (tmpinfo) {
389                                                 free(tmpinfo);
390                                                 tmpinfo = NULL;
391                                         }
392                                         return NATIVEINSTALLER_ERR_NEED_USER_CONFIRMATION;
393                         case 0:
394                                         /*return */
395                                         if (info) {
396                                                 free(info);
397                                                 info = NULL;
398                                         }
399                                         if (tmpinfo) {
400                                                 free(tmpinfo);
401                                                 tmpinfo = NULL;
402                                         }
403                                         _set_backend_state_info(DPKG_REQUEST_COMPLETED);
404                                         return NATIVEINSTALLER_PACKAGE_NOT_UPGRADED;
405                         case 1:
406                                         /*continue with downgrade */
407                                         _set_backend_state_info
408                                         (GOT_PACKAGE_INFO_SUCCESSFULLY);
409                                         err =
410                                         _pkgmgr_dpkg_upgrade_pkg(pkgfilepath,
411                                                          installoptions);
412                                         if (err != 0) {
413                                                 d_msg_backend(DEBUG_ERR,
414                                                       "upgrade complete with error(%d)\n",
415                                                       err);
416                                                 if (info) {
417                                                         free(info);
418                                                         info = NULL;
419                                                 }
420                                                 if (tmpinfo) {
421                                                         free(tmpinfo);
422                                                         tmpinfo = NULL;
423                                                 }
424                                                 return err;
425                                         }
426                                         _set_backend_state_info(DPKG_REQUEST_COMPLETED);
427                                         if (info) {
428                                                 free(info);
429                                                 info = NULL;
430                                         }
431                                         if (tmpinfo) {
432                                                 free(tmpinfo);
433                                                 tmpinfo = NULL;
434                                         }
435                                         return NATIVEINSTALLER_SUCCESS;
436                                         
437                         }
438                 
439
440                 }
441
442         } else {
443                 _set_backend_state_info(GOT_PACKAGE_INFO_SUCCESSFULLY);
444                 err = _pkgmgr_dpkg_install_pkg(pkgfilepath, installoptions);
445                 if (err != 0) {
446                         d_msg_backend(DEBUG_ERR,
447                                       "install complete with error(%d)\n", err);
448                         if (info) {
449                                 free(info);
450                                 info = NULL;
451                         }
452                         return err;
453                 }
454
455                 _set_backend_state_info(DPKG_REQUEST_COMPLETED);
456                 if (info) {
457                         free(info);
458                         info = NULL;
459                 }
460                 return NATIVEINSTALLER_SUCCESS;
461         }
462         if (tmpinfo) {
463                 free(tmpinfo);
464                 tmpinfo = NULL;
465         }
466         return NATIVEINSTALLER_SUCCESS;
467 }
468
469 int _pkgmgr_package_uninstall(char *pkgname)
470 {
471         int ret = 0;
472
473         pkginfo *tmppkginfo = _pkgmgr_get_installed_pkg_info(pkgname);
474         if (tmppkginfo == NULL)
475                 return NATIVEINSTALLER_ERR_PACKAGE_NOT_INSTALLED;
476
477         free(tmppkginfo);
478 #ifndef SEND_PKGPATH
479         gptrpkgname = strdup(pkgname);
480         _broadcast_status_notification(pkgname, "start", "uninstall");
481         _broadcast_status_notification(pkgname, "command", "Uninstall");
482 #endif
483         _set_backend_state_info(GOT_PACKAGE_INFO_SUCCESSFULLY);
484         /* call remove package using package installer module */
485         ret = _pkgmgr_dpkg_uninstall_pkg(pkgname);
486
487         _set_backend_state_info(DPKG_REQUEST_COMPLETED);
488
489         return ret;
490 }
491
492 int _pkgmgr_clear_private_data(char *pkgname)
493 {
494         if (pkgname == NULL)
495                 return NATIVEINSTALLER_ERR_WRONG_PARAM;
496         char dir_path[256] = {'\0'};
497         int ret = -1;
498         snprintf(dir_path, 255, "/opt/apps/%s/data/", pkgname);
499         ret = __recursive_delete_dir(dir_path);
500         return ret;
501 }