Modify symbolic of rpm-backend in post script for TC-321
[platform/core/base/rpm-installer.git] / backend / src / core / rpm-installer-tool.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 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <getopt.h>
27 #include <fcntl.h>
28 #include <dirent.h>
29 #include <unistd.h>
30 #include <ctype.h>
31 #include <rpmlib.h>
32 #include <header.h>
33 #include <rpmts.h>
34 #include <rpmdb.h>
35 #include "rpm-installer.h"
36 #include "rpm-frontend.h"
37 #include <pkgmgr_installer.h>
38
39 #define RPM     "/usr/etc/package-manager/backend/rpm"
40
41 char *gpkgname = NULL;
42 extern char scrolllabel[256];
43 extern int move_type;
44 enum optionsflags {
45         INVALID_OPTIONS = 0,
46         FORCE_OVERWITE = 1,
47         IGNORE_DEPENDS = 2,
48 };
49
50 struct ri_backend_data_t {
51         int req_cmd;
52         char *cmd_string;
53         char *pkgid;
54         int force_overwrite;
55 };
56
57 typedef struct ri_backend_data_t ri_backend_data;
58 static int __ri_native_recovery(int lastbackstate);
59 static int __ri_uninstall_package(char *pkgid);
60 static int __ri_clear_private_data(char *pkgid);
61 static int __ri_move_package(char *pkgid, int move_type);
62 static inline int __ri_read_proc(const char *path, char *buf, int size);
63 static inline int __ri_find_pid_by_cmdline(const char *dname,
64                                            const char *cmdline,
65                                            const char *priv);
66 static bool __ri_is_another_instance_running(const char *exepath);
67
68 static int __ri_uninstall_package(char *pkgid)
69 {
70
71         if (pkgid == NULL)
72                 return RPM_INSTALLER_ERR_WRONG_PARAM;
73         int ret = 0;
74         ret = _rpm_installer_package_uninstall(pkgid);
75         if (ret == RPM_INSTALLER_ERR_PACKAGE_NOT_INSTALLED) {
76                 _d_msg(DEBUG_ERR, "[__ri_uninstall_package]%s "
77                        "not installed\n", pkgid);
78         } else if (ret != 0) {
79                 _d_msg(DEBUG_ERR,
80                        "[__ri_uninstall_package]%s uninstall failed(%d)\n",
81                        pkgid, ret);
82         } else {
83                 _d_msg(DEBUG_ERR,
84                        "[__ri_uninstall_package]%s successfully uninstalled\n",
85                        pkgid);
86         }
87         return ret;
88 }
89
90 static int __ri_clear_private_data(char *pkgid)
91 {
92         if (pkgid == NULL)
93                 return RPM_INSTALLER_ERR_WRONG_PARAM;
94         int ret = 0;
95         ret = _rpm_installer_clear_private_data(pkgid);
96         if (ret == RPM_INSTALLER_SUCCESS) {
97                 _d_msg(DEBUG_ERR,
98                        "[__clear_private_data]%s clear data successful\n",
99                        pkgid);
100         } else {
101                 _d_msg(DEBUG_ERR,
102                        "[__clear_private_data]%s clear data failed(%d)\n",
103                        pkgid, ret);
104         }
105         return ret;
106 }
107
108 static int __ri_move_package(char *pkgid, int move_type)
109 {
110         if (pkgid == NULL)
111                 return RPM_INSTALLER_ERR_WRONG_PARAM;
112         int ret = 0;
113         ret = _rpm_move_pkg(pkgid, move_type);
114         if (ret == RPM_INSTALLER_SUCCESS) {
115                 _d_msg(DEBUG_ERR,
116                        "[__ri_move_package]%s move successful\n",
117                        pkgid);
118         } else {
119                 _d_msg(DEBUG_ERR,
120                        "[__ri_move_package]%s move failed(%d)\n",
121                        pkgid, ret);
122         }
123         return ret;
124 }
125
126 static inline int __ri_read_proc(const char *path, char *buf, int size)
127 {
128         int fd;
129         int ret;
130
131         if (buf == NULL || path == NULL)
132                 return -1;
133
134         fd = open(path, O_RDONLY);
135         if (fd < 0)
136                 return -1;
137
138         ret = read(fd, buf, size - 1);
139         if (ret <= 0) {
140                 close(fd);
141                 return -1;
142         } else
143                 buf[ret] = 0;
144
145         close(fd);
146
147         return ret;
148 }
149
150 static inline int __ri_find_pid_by_cmdline(const char *dname,
151                                            const char *cmdline,
152                                            const char *priv)
153 {
154         int pid = 0;
155         if (strncmp(cmdline, priv, strlen(RPM)) == 0) {
156                 pid = atoi(dname);
157                 if (pid != getpgid(pid))
158                         pid = 0;
159                 if (pid == getpid())
160                         pid = 0;
161         }
162
163         return pid;
164 }
165
166 static bool __ri_is_another_instance_running(const char *exepath)
167 {
168         DIR *dp;
169         struct dirent *dentry;
170         int pid;
171         int ret;
172         char buf[256] = { 0, };
173         char buf1[256] = { 0, };
174         dp = opendir("/proc");
175         if (dp == NULL) {
176                 return 0;
177         }
178         while ((dentry = readdir(dp)) != NULL) {
179                 if (!isdigit(dentry->d_name[0]))
180                         continue;
181                 snprintf(buf, sizeof(buf), "/proc/%s/cmdline", dentry->d_name);
182                 ret = __ri_read_proc(buf, buf1, sizeof(buf));
183                 if (ret <= 0)
184                         continue;
185                 pid = __ri_find_pid_by_cmdline(dentry->d_name, buf1, exepath);
186                 if (pid > 0) {
187                         closedir(dp);
188                         return 1;
189                 }
190         }
191
192         closedir(dp);
193         return 0;
194
195 }
196
197 static int __ri_native_recovery(int lastbackstate)
198 {
199         char *pn = NULL;
200         int lreq;
201         int opt;
202         int err = 0;
203         char *installoptions = NULL;
204
205         _d_msg(DEBUG_INFO, "Rpm Installer Recovery Entry \n");
206
207         /* which package it was installing and what was state at that time */
208         _ri_get_last_input_info(&pn, &lreq, &opt);
209
210         switch (lastbackstate) {
211         case REQUEST_ACCEPTED:
212         case GOT_PACKAGE_INFO_SUCCESSFULLY:
213                 /*
214                  * restart the last operation
215                  */
216                 _d_msg(DEBUG_INFO,
217                               "Rpm Installer Recovery started. state=%d \n", lastbackstate);
218                 switch (lreq) {
219                 case INSTALL_CMD:
220                         err =
221                             _rpm_installer_package_install(pn, true, "--force");
222                         if (err)
223                                 goto RECOVERYERROR;
224                         break;
225
226                 case DELETE_CMD:
227                         err = _rpm_installer_package_uninstall(pn);
228                         if (err)
229                                 goto RECOVERYERROR;
230                         break;
231
232                 case CLEARDATA_CMD:
233                 case MOVE_CMD:
234                 case RECOVER_CMD:
235                         /*TODO*/
236                         _d_msg(DEBUG_INFO,
237                                         "Recovery of command(%d) is to be implemented\n", lreq);
238                         return 0;
239                 }
240                 _d_msg(DEBUG_INFO,
241                               " Rpm Installer Recovery Ended \n");
242                 break;
243         case REQUEST_COMPLETED:
244                 _d_msg(DEBUG_INFO,
245                               " Rpm Installer Recovery. Nothing To Be Done\n");
246                 _ri_set_backend_state_info(REQUEST_COMPLETED);
247                 break;
248
249         case REQUEST_PENDING:
250                 _d_msg(DEBUG_INFO,
251                                 "Rpm Installer Recovery started. state=%d\n", lastbackstate);
252                 /*Only package downgradation can be the case*/
253                 err = _rpm_installer_package_install(pn, true, "--force");
254                 if (err != RPM_INSTALLER_SUCCESS &&
255                         err != RPM_INSTALLER_ERR_NEED_USER_CONFIRMATION) {
256                         goto RECOVERYERROR;
257                 }
258                 _d_msg(DEBUG_INFO,
259                               " Rpm Installer Recovery ended \n");
260                 _ri_set_backend_state_info(REQUEST_COMPLETED);
261                 break;
262
263         default:
264                 /*
265                  * Unknown state
266                  * No need to recover
267                  */
268                 _d_msg(DEBUG_INFO,
269                               " Rpm Installer Recovery Default state \n");
270                 break;
271
272         }
273         return 0;
274
275  RECOVERYERROR:
276         _d_msg(DEBUG_ERR, "Error in Recovery error number = (%d)\n",
277                       err);
278         return err;
279
280 }
281
282 int _rpm_backend_interface(char *keyid, char *pkgid, char *reqcommand)
283 {
284         int ret = -1;
285         ri_backend_data data = { 0 };
286         int backendstate;
287         rpmRC rc;
288         if (reqcommand == NULL) {
289                 _d_msg(DEBUG_ERR, "reqcommand is NULL\n");
290                 return RPM_INSTALLER_ERR_WRONG_PARAM;
291         }
292         if (keyid == NULL || pkgid == NULL) {
293                 if (strncmp(reqcommand, "recover", strlen("recover"))) {
294                         _d_msg(DEBUG_ERR, " Either keyid/pkgid is NULL\n");
295                         return RPM_INSTALLER_ERR_WRONG_PARAM;
296                 }
297         }
298
299         if (strncmp(reqcommand, "install", strlen("install")) == 0) {
300                 data.req_cmd = INSTALL_CMD;
301                 data.cmd_string = strdup("install");
302                 if (data.cmd_string == NULL) {
303                         _d_msg(DEBUG_ERR,
304                                "strdup failed due to insufficient memory\n");
305                 }
306         } else if (strncmp(reqcommand, "remove", strlen("remove")) == 0) {
307                 data.req_cmd = DELETE_CMD;
308                 data.cmd_string = strdup("uninstall");
309                 if (data.cmd_string == NULL) {
310                         _d_msg(DEBUG_ERR,
311                                "strdup failed due to insufficient memory\n");
312                 }
313         } else if (strncmp(reqcommand, "recover", strlen("recover")) == 0) {
314                 data.req_cmd = RECOVER_CMD;
315                 data.cmd_string = strdup("recover");
316                 if (data.cmd_string == NULL) {
317                         _d_msg(DEBUG_ERR,
318                                "strdup failed due to insufficient memory\n");
319                 }
320         } else if (strncmp(reqcommand, "cleardata", strlen("cleardata")) == 0) {
321                 data.req_cmd = CLEARDATA_CMD;
322                 data.cmd_string = strdup("cleardata");
323                 if (data.cmd_string == NULL) {
324                         _d_msg(DEBUG_ERR,
325                                "strdup failed due to insufficient memory\n");
326                 }
327         } else if (strncmp(reqcommand, "move", strlen("move")) == 0) {
328                 data.req_cmd = MOVE_CMD;
329                 data.cmd_string = strdup("move");
330                 if (data.cmd_string == NULL) {
331                         _d_msg(DEBUG_ERR,
332                                "strdup failed due to insufficient memory\n");
333                 }
334         } else {
335                 _d_msg(DEBUG_INFO, "wrong input parameter\n");
336                 _d_msg(DEBUG_RESULT, "%d\n", RPM_INSTALLER_ERR_WRONG_PARAM);
337                 return RPM_INSTALLER_ERR_WRONG_PARAM;
338         }
339
340         data.pkgid = pkgid;
341         backendstate = _ri_get_backend_state();
342
343         rc = rpmReadConfigFiles(NULL, NULL);
344         if (rc == RPMRC_OK) {
345                 _d_msg(DEBUG_INFO, "Successfully read rpm configuration\n");
346         } else {
347                 _d_msg(DEBUG_ERR, "Unable to read RPM configuration.\n");
348                 return RPM_INSTALLER_ERR_INTERNAL;
349         }
350
351         if (RECOVER_CMD == data.req_cmd) {
352                 if (0 == backendstate) {
353                         int lastbackstate;
354
355                         /* check the current state of backend */
356                         lastbackstate = _ri_get_backend_state_info();
357
358                         if (REQUEST_COMPLETED == lastbackstate) {
359                                 _d_msg(DEBUG_INFO,
360                                        " Rpm Installer recovery is in REQUEST_COMPLETED  \n");
361                                 snprintf(scrolllabel, sizeof(scrolllabel),
362                                          "No Recovery Needed");
363                         } else
364                                 ret = __ri_native_recovery(lastbackstate);
365                         if (ret == 0)
366                                 snprintf(scrolllabel, sizeof(scrolllabel),
367                                          "Recovery Success");
368                         else
369                                 snprintf(scrolllabel, sizeof(scrolllabel),
370                                         "Recovery Failed");
371
372                         /* set the backend state as completed */
373                         _ri_set_backend_state(1);
374                 } else {
375                         /* nothing to recover */
376                         _d_msg(DEBUG_INFO,
377                                " Rpm Installer recovery Nothing to be done\n");
378                         ret = 0;
379                         snprintf(scrolllabel, sizeof(scrolllabel),
380                                  "No Recovery Needed");
381                 }
382                 _d_msg(DEBUG_RESULT, "%d\n", ret);
383                 return ret;
384
385         }
386         if (backendstate == 0) {
387
388                 /* Non Recovery case
389                  *
390                  * Another Instance may be running
391                  * or something went wrong in last execution
392                  * Check for it
393                  */
394                 if (__ri_is_another_instance_running(RPM)) {
395                         if (data.pkgid) {
396                                 _ri_broadcast_status_notification
397                                     (data.pkgid, "error",
398                                      "Another Instance Running");
399                                 _ri_stat_cb(data.pkgid, "error",
400                                             "Another Instance Running");
401                                 _ri_broadcast_status_notification
402                                     (data.pkgid, "end", "fail");
403                                 _ri_stat_cb(data.pkgid, "end",
404                                             "fail");
405                         } else {
406                                 _ri_broadcast_status_notification
407                                     ("unknown", "error",
408                                      "Another Instance Running");
409                                 _ri_stat_cb("unknown", "error",
410                                             "Another Instance Running");
411                                 _ri_broadcast_status_notification
412                                     ("unknown", "end", "fail");
413                                 _ri_stat_cb("unknown", "end", "fail");
414                         }
415                         _d_msg(DEBUG_INFO,
416                                "Request Failed as "
417                                "Another Instance is running \n");
418                         ret = RPM_INSTALLER_ERR_RESOURCE_BUSY;
419                         return ret;
420                 } else {
421                         int lastbackstate;
422
423                         /* check the current state of backend */
424                         lastbackstate = _ri_get_backend_state_info();
425                         /* Publish Notification that backend has started */
426                         _ri_broadcast_status_notification(data.pkgid,
427                                                           "start",
428                                                           data.cmd_string);
429                         _ri_broadcast_status_notification(data.pkgid,
430                                                           "command",
431                                                           data.cmd_string);
432                         if (REQUEST_COMPLETED == lastbackstate) {
433                                 _d_msg(DEBUG_INFO,
434                                        " Rpm Installer recovery"
435                                        " is in REQUEST_COMPLETED  \n");
436                                 ret = 0;
437                         } else
438                                 ret = __ri_native_recovery(lastbackstate);
439                         if (ret != 0) {
440                                 _d_msg(DEBUG_INFO,
441                                         "recovery of last request failed\n");
442                         } else {
443                                 _d_msg(DEBUG_INFO,
444                                        "recovery of last request success\n");
445                         }
446
447                         /* set the backend state as completed */
448                         _ri_set_backend_state(1);
449                 }
450         }
451
452         /* set the backend state as started for the current request*/
453         _ri_set_backend_state(0);
454
455 #ifdef SEND_PKGPATH
456         gpkgname = strdup(data.pkgid);
457
458         /* Publish Notification that backend has started */
459         if (data.pkgid)
460                 _ri_broadcast_status_notification(data.pkgid, "start",
461                                                   data.cmd_string);
462         else
463                 _ri_broadcast_status_notification("unknown", "start",
464                                                   data.cmd_string);
465 #endif
466
467         _ri_set_backend_state_info(REQUEST_ACCEPTED);
468
469         /* Set the input request info */
470         _ri_save_last_input_info(data.pkgid, data.req_cmd,
471                                  data.force_overwrite);
472
473         switch (data.req_cmd) {
474         case INSTALL_CMD:
475                 {
476                         _d_msg(DEBUG_INFO, "[%s] --install %s\n",
477                                "backend", data.pkgid);
478 #ifdef SEND_PKGPATH
479                         _ri_broadcast_status_notification(data.pkgid,
480                                                           "command", "Install");
481 #endif
482                         if (data.force_overwrite == FORCE_OVERWITE) {
483                                 _d_msg(DEBUG_INFO,
484                                        "[%s] --install %s --force-overwrite\n",
485                                        "backend", data.pkgid);
486                                 ret =
487                                     _rpm_installer_package_install
488                                     (data.pkgid, true, "--force");
489                         } else {
490                                 _d_msg(DEBUG_INFO, "[%s] --install %s\n",
491                                        "backend", data.pkgid);
492                                 ret =
493                                     _rpm_installer_package_install
494                                     (data.pkgid, false, NULL);
495                         }
496                         if (ret == RPM_INSTALLER_ERR_NEED_USER_CONFIRMATION) {
497                                 break;
498                         } else if (ret == RPM_INSTALLER_SUCCESS) {
499                                 _d_msg(DEBUG_INFO, "install success\n");
500                                 _ri_broadcast_status_notification(data.pkgid,
501                                                                   "end", "ok");
502                                 _ri_stat_cb(data.pkgid, "end", "ok");
503                         } else {
504
505                                 char *errstr = NULL;
506                                 _ri_error_no_to_string(ret, &errstr);
507                                 _ri_broadcast_status_notification(data.pkgid,
508                                                                   "error",
509                                                                   errstr);
510                                 _ri_stat_cb(data.pkgid, "error", errstr);
511                                 _ri_broadcast_status_notification(data.pkgid,
512                                                                   "end",
513                                                                   "fail");
514                                 sleep(2);
515                                 _ri_stat_cb(data.pkgid, "end", "fail");
516                                 _d_msg(DEBUG_ERR,
517                                        "install failed with err(%d) (%s)\n",
518                                        ret, errstr);
519                         }
520                 }
521                 break;
522         case DELETE_CMD:
523                 {
524                         _d_msg(DEBUG_INFO, "[%s] uninstall %s\n",
525                                "backend", data.pkgid);
526 #ifdef SEND_PKGPATH
527                         _ri_broadcast_status_notification(data.pkgid,
528                                                           "command", "Remove");
529 #endif
530                         ret = __ri_uninstall_package(data.pkgid);
531                         if (ret != 0) {
532                                 char *errstr = NULL;
533                                 _ri_error_no_to_string(ret, &errstr);
534                                 _ri_broadcast_status_notification(data.pkgid,
535                                                                   "error",
536                                                                   errstr);
537                                 _ri_stat_cb(data.pkgid, "error", errstr);
538                                 sleep(2);
539                                 _ri_broadcast_status_notification(data.pkgid,
540                                                                   "end",
541                                                                   "fail");
542                                 _ri_stat_cb(data.pkgid, "end", "fail");
543                                 _d_msg(DEBUG_ERR,
544                                        "remove failed with err(%d) (%s)\n",
545                                        ret, errstr);
546                         } else {
547                                 _d_msg(DEBUG_INFO, "remove success\n");
548                                 _ri_broadcast_status_notification(data.pkgid,
549                                                                   "end", "ok");
550                                 _ri_stat_cb(data.pkgid, "end", "ok");
551                         }
552                 }
553                 break;
554         case CLEARDATA_CMD:
555                 {
556                         _d_msg(DEBUG_INFO, "[%s] clear data %s\n",
557                                "backend", data.pkgid);
558 #ifdef SEND_PKGPATH
559                         _ri_broadcast_status_notification(data.pkgid,
560                                                           "command", "clear");
561 #endif
562                         ret = __ri_clear_private_data(data.pkgid);
563                         if (ret != 0) {
564                                 char *errstr = NULL;
565                                 _ri_error_no_to_string(ret, &errstr);
566                                 _ri_broadcast_status_notification(data.pkgid,
567                                                                   "error",
568                                                                   errstr);
569                                 _ri_stat_cb(data.pkgid, "error", errstr);
570                                 _ri_broadcast_status_notification(data.pkgid,
571                                                                   "end",
572                                                                   "fail");
573                                 _ri_stat_cb(data.pkgid, "end", "fail");
574                                 _d_msg(DEBUG_ERR,
575                                        "clear data failed with err(%d) (%s)\n",
576                                        ret, errstr);
577                         } else {
578                                 _d_msg(DEBUG_INFO, "clear data success\n");
579                                 _ri_broadcast_status_notification(data.pkgid,
580                                                                   "end", "ok");
581                                 _ri_stat_cb(data.pkgid, "end", "ok");
582                         }
583                         break;
584                 }
585         case MOVE_CMD:
586                 {
587                         _d_msg(DEBUG_INFO, "[%s] move %s\n",
588                                "backend", data.pkgid);
589 #ifdef SEND_PKGPATH
590                         _ri_broadcast_status_notification(data.pkgid,
591                                                           "command", "move");
592 #endif
593                         ret = __ri_move_package(data.pkgid, move_type);
594                         if (ret != 0) {
595                                 char *errstr = NULL;
596                                 _ri_error_no_to_string(ret, &errstr);
597                                 _ri_broadcast_status_notification(data.pkgid,
598                                                                   "error",
599                                                                   errstr);
600                                 _ri_stat_cb(data.pkgid, "error", errstr);
601                                 _ri_broadcast_status_notification(data.pkgid,
602                                                                   "end",
603                                                                   "fail");
604                                 _ri_stat_cb(data.pkgid, "end", "fail");
605                                 _d_msg(DEBUG_ERR,
606                                        "move failed with err(%d) (%s)\n",
607                                        ret, errstr);
608                         } else {
609                                 _d_msg(DEBUG_INFO, "move success\n");
610                                 _ri_broadcast_status_notification(data.pkgid,
611                                                                   "end", "ok");
612                                 _ri_stat_cb(data.pkgid, "end", "ok");
613                         }
614                         break;
615                 }
616         default:
617                 {
618                         _ri_broadcast_status_notification("unknown", "command",
619                                                           "unknown");
620                         _ri_broadcast_status_notification("unknown", "error",
621                                                           "not supported");
622                         _ri_stat_cb("unknown", "error", "not supported");
623                         _ri_broadcast_status_notification("unknown",
624                                                           "end", "fail");
625                         _ri_stat_cb("unknown", "end", "fail");
626                         _d_msg(DEBUG_ERR, "unknown command \n");
627                         ret = RPM_INSTALLER_ERR_WRONG_PARAM;
628                 }
629         }
630
631         if (gpkgname) {
632                 free(gpkgname);
633                 gpkgname = NULL;
634         }
635
636         if (data.cmd_string) {
637                 free(data.cmd_string);
638                 data.cmd_string = NULL;
639         }
640
641         if (_ri_get_backend_state_info() != REQUEST_PENDING) {
642                 _ri_set_backend_state_info(REQUEST_COMPLETED);
643                 /* set the backend state as completed */
644                 _ri_set_backend_state(1);
645                 _d_msg(DEBUG_RESULT, "%d\n", ret);
646                 _d_msg_deinit();
647         }
648         return ret;
649 }