4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
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>
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
35 #include "nativeinstaller.h"
36 #include<pkgmgr_installer.h>
38 #define DEB "/usr/etc/package-manager/backend/deb"
40 char *gptrpkgname = NULL;
41 extern char scrolllabel[256];
43 INVALID_BACKEND_CMD = 0,
44 INSTALL_BACKEND_CMD = 1,
45 REMOVE_BACKEND_CMD = 2,
46 UPGRADE_BACKEND_CMD = 3,
47 AUDIT_BACKEND_CMD = 4,
48 RECOVER_BACKEND_CMD = 5,
61 char *preq_cmd_string;
66 static int __pkgmgr_show_pkginfo(char *pkgname);
67 static int __uninstall_package(char *pkgname);
68 static int __clear_private_data(char *pkgname);
69 static void __show_usage();
70 static int __native_recovery(int lastbackstate);
71 static inline int __read_proc(const char *path, char *buf, int size);
72 static inline int __find_pid_by_cmdline(const char *dname,
73 const char *cmdline, const char *priv);
74 static bool __is_another_instance_running(const char *exepath);
75 int main_of_backend(char *keyid, char *pkgname, char *reqcommand);
77 static int __pkgmgr_show_pkginfo(char *pkgname)
81 return NATIVEINSTALLER_ERR_WRONG_PARAM;
83 info = _pkgmgr_get_installed_pkg_info(pkgname);
85 d_msg_backend(DEBUG_ERR, "(%s) package not exist\n", pkgname);
87 printf("----------------------------\n");
88 printf("PackageName\t: %s\n", info->package_name);
89 printf("Version\t\t: %s\n", info->version);
90 printf("----------------------------\n");
99 static int __uninstall_package(char *pkgname)
103 return NATIVEINSTALLER_ERR_WRONG_PARAM;
105 ret = _pkgmgr_package_uninstall(pkgname);
106 if (ret == NATIVEINSTALLER_ERR_PACKAGE_NOT_INSTALLED) {
107 d_msg_backend(DEBUG_ERR, "[__uninstall_package]%s "
110 } else if (ret != 0) {
111 d_msg_backend(DEBUG_ERR,
112 "[__uninstall_package]%s uninstall failed(%d)\n",
115 d_msg_backend(DEBUG_ERR,
116 "[__uninstall_package]%s successfully uninstalled\n",
122 static int __clear_private_data(char *pkgname)
126 return NATIVEINSTALLER_ERR_WRONG_PARAM;
128 ret = _pkgmgr_clear_private_data(pkgname);
129 if (ret == NATIVEINSTALLER_SUCCESS) {
130 d_msg_backend(DEBUG_ERR,
131 "[__clear_private_data]%s clear data successful\n", pkgname);
133 d_msg_backend(DEBUG_ERR,
134 "[__clear_private_data]%s clear data failed(%d)\n", pkgname, ret);
140 static void __show_usage()
143 ("\nbackend usage\n backend <keyid> <pkgname> <commands> \n\n");
144 printf("<Commands> \n");
146 ("\tkeyid <pkgname> install :"
147 " install package <PackageFile>\n");
149 ("\tkeyid <pkgname> remove : "
150 "uninstall package <PackageName>\n");
152 ("\tkeyid dummy recover :"
153 " recover the system\n");
156 static int __native_recovery(int lastbackstate)
158 char *pkgname = NULL;
162 pkginfo *ptmp_pkginfo = NULL;
163 bool already_installed = false;
166 char *installoptions = NULL;
168 d_msg_backend(DEBUG_INFO, "Native Installer recovery Entry \n");
170 /* which package it was installing and what was state at that time */
171 _get_last_input_info(&pkgname, &lastreq, &options);
173 switch (lastbackstate) {
174 case REQUEST_ACCEPTED:
176 * we can restart the last operations
177 * once again as request was only accepted
178 * but nothing had done
179 * It will be same as restarting the last request again
181 d_msg_backend(DEBUG_INFO,
182 "Native Installer recovery REQUEST_ACCEPTED started \n");
184 case INSTALL_BACKEND_CMD:
186 _pkgmgr_get_pkg_info(pkgname, &err, &already_installed);
187 if (err != 0 || ptmp_pkginfo == NULL) {
188 if (ptmp_pkginfo != NULL) {
197 case REMOVE_BACKEND_CMD:
198 ptmp_pkginfo = _pkgmgr_get_installed_pkg_info(pkgname);
199 if (ptmp_pkginfo == NULL)
201 if (ptmp_pkginfo != NULL) {
207 d_msg_backend(DEBUG_INFO,
208 " Native Installer recovery REQUEST_ACCEPTED Ended \n");
210 _set_backend_state_info(GOT_PACKAGE_INFO_SUCCESSFULLY);
212 case GOT_PACKAGE_INFO_SUCCESSFULLY:
213 d_msg_backend(DEBUG_INFO,
214 " Native Installer recovery "
215 "GOT_PACKAGE_INFO_SUCCESSFULLY started \n");
217 * Package information is been read successfully
218 * For Install and upgrade: This means
219 * manifest file has been successfully processed
220 * For remove: This means
221 * package was already installed.
224 case INSTALL_BACKEND_CMD:
225 err = _pkgmgr_dpkg_install_pkg(pkgname, installoptions);
227 d_msg_backend(DEBUG_ERR,
228 "_pkgmgr_dpkg_install_pkg "
229 "return error(%d)\n",
235 case REMOVE_BACKEND_CMD:
236 err = _pkgmgr_dpkg_uninstall_pkg(pkgname);
238 d_msg_backend(DEBUG_ERR,
239 "_pkgmgr_dpkg_uninstall_pkg "
240 "return error(%d)\n",
242 /* TO DO clean db and menu screen */
247 d_msg_backend(DEBUG_INFO,
248 " Native Installer recovery "
249 "GOT_PACKAGE_INFO_SUCCESSFULLY ended \n");
250 _set_backend_state_info(DPKG_REQUEST_COMPLETED);
252 case DPKG_REQUEST_COMPLETED:
253 d_msg_backend(DEBUG_INFO,
254 " Native Installer recovery "
255 "DPKG_REQUEST_COMPLETED started \n");
257 d_msg_backend(DEBUG_INFO,
258 " Native Installer recovery"
259 " DPKG_REQUEST_COMPLETED ended \n");
261 _set_backend_state_info(REQUEST_COMPLETED);
268 d_msg_backend(DEBUG_INFO,
269 " Native Installer recovery Default state \n");
276 d_msg_backend(DEBUG_ERR, "Error in Recovery error number = (%d)\n",
281 static inline int __read_proc(const char *path, char *buf, int size)
286 if (buf == NULL || path == NULL)
289 fd = open(path, O_RDONLY);
293 ret = read(fd, buf, size - 1);
305 static inline int __find_pid_by_cmdline(const char *dname,
306 const char *cmdline, const char *priv)
309 if (strncmp(cmdline, priv, strlen(DEB)) == 0) {
311 if (pid != getpgid(pid))
320 static bool __is_another_instance_running(const char *exepath)
323 struct dirent *dentry;
326 char buf[256] = {0,};
327 char buf1[256] = {0,};
328 dp = opendir("/proc");
332 while ((dentry = readdir(dp)) != NULL) {
333 if (!isdigit(dentry->d_name[0]))
335 snprintf(buf, sizeof(buf), "/proc/%s/cmdline", dentry->d_name);
336 ret = __read_proc(buf, buf1, sizeof(buf));
339 pid = __find_pid_by_cmdline(dentry->d_name, buf1, exepath);
352 * check if status some other instance is running or not
353 * if status file exist then back end exit with reason code
354 * another instance is in progress
356 * We can use a vconf entry for checking whether back end
357 * is running properly or not
358 * When we start the back end, we check the value of vconf,
359 * there are following scenario
360 * 1) Back end start for the first time. It mean this is the
361 * first time we are calling backend.
362 * then ther will not be any vconf entry
363 * 2) Back end was successfully complete the requested operation
364 * vconf entry will be completed state
365 * 3) Back end had not able to complete the operation and
366 * some problem occured in installation like segmentation fault,
367 * Poweroff, low battery.
368 * vconf entry will be in started state
373 /* int main(int argc, char **argv) */
374 int main_of_backend(char *keyid, char *pkgname, char *reqcommand)
377 struct parsedout_st pardata = { 0 };
379 _d_msg_init("backend");
380 d_msg_backend(DEBUG_RESULT, "Backend version: %s\n",
381 NATIVE_INSTALLER_VERSION);
382 if (reqcommand == NULL) {
383 d_msg_backend(DEBUG_ERR,"reqcommand is NULL\n");
384 return NATIVEINSTALLER_ERR_WRONG_PARAM;
386 if (strcmp(reqcommand, "recover") != 0) {
387 if (keyid == NULL || pkgname == NULL) {
388 d_msg_backend(DEBUG_ERR,
389 " Either keyid/pkgname is NULL\n");
390 return NATIVEINSTALLER_ERR_WRONG_PARAM;
394 if (strcmp(reqcommand, "install") == 0) {
395 pardata.reqcommand = INSTALL_BACKEND_CMD;
396 pardata.preq_cmd_string = strdup("install");
397 if (pardata.preq_cmd_string == NULL) {
398 d_msg_backend(DEBUG_ERR,
399 "strdup failed due to insufficient memory\n");
401 } else if (strcmp(reqcommand, "remove") == 0) {
402 pardata.reqcommand = REMOVE_BACKEND_CMD;
403 pardata.preq_cmd_string = strdup("uninstall");
404 if (pardata.preq_cmd_string == NULL) {
405 d_msg_backend(DEBUG_ERR,
406 "strdup failed due to insufficient memory\n");
408 } else if (strcmp(reqcommand, "clear") == 0) {
409 pardata.reqcommand = CLEAR_BACKEND_CMD;
410 pardata.preq_cmd_string = strdup("clear");
411 if (pardata.preq_cmd_string == NULL) {
412 d_msg_backend(DEBUG_ERR,
413 "strdup failed due to insufficient memory\n");
415 }else if (strcmp(reqcommand, "recover") == 0) {
416 pardata.reqcommand = RECOVER_BACKEND_CMD;
417 pardata.preq_cmd_string = strdup("recover");
418 if (pardata.preq_cmd_string == NULL) {
419 d_msg_backend(DEBUG_ERR,
420 "strdup failed due to insufficient memory\n");
423 d_msg_backend(DEBUG_INFO, "wrong input parameter\n");
424 d_msg_backend(DEBUG_RESULT, "%d\n",
425 NATIVEINSTALLER_ERR_WRONG_PARAM);
426 return NATIVEINSTALLER_ERR_WRONG_PARAM;
429 pardata.ppkgname = pkgname;
430 backendstate = _get_backend_state();
432 if (RECOVER_BACKEND_CMD == pardata.reqcommand) {
433 if (0 == backendstate) {
436 /* check the current state of backend */
437 lastbackstate = _get_backend_state_info();
439 if (REQUEST_COMPLETED == lastbackstate) {
440 d_msg_backend(DEBUG_INFO,
441 " Native Installer recovery is in REQUEST_COMPLETED \n");
442 snprintf(scrolllabel, sizeof(scrolllabel), "No Recovery Needed");
444 ret = __native_recovery(lastbackstate);
446 snprintf(scrolllabel, sizeof(scrolllabel), "Recovery Success");
448 /* set the backend state as completed */
449 _set_backend_state(1);
451 /* nothing to recover */
452 d_msg_backend(DEBUG_INFO,
453 " Native Installer recovery Nothing need to be done\n");
455 snprintf(scrolllabel, sizeof(scrolllabel), "No Recovery Needed");
457 d_msg_backend(DEBUG_RESULT, "%d\n", ret);
461 /* Non Recovery case */
463 if (0 == backendstate) {
464 /* back state is in wrong state;
465 * either other instance is running
466 * or some thing went wrong in last execution of backend
468 /* if last execution had problem
469 * then request is for the same operation again
470 * then reexecute the same command
471 * other wise roll back the old command
473 char *pkgname = NULL;
477 /* which package it was installing and
478 what was state at that time */
479 _get_last_input_info(&pkgname, &lastreq, &options);
481 if ((pardata.reqcommand == lastreq) &&
482 (strcmp(pkgname, pardata.ppkgname) == 0)) {
483 /* same command is executed for 2nd time */
484 /* this is same as recover */
488 /* check the current state of backend */
489 lastbackstate = _get_backend_state_info();
490 /* Publish Notification that backend has started */
491 _broadcast_status_notification(pardata.ppkgname,
493 pardata.preq_cmd_string);
494 _broadcast_status_notification(pardata.ppkgname,
496 pardata.preq_cmd_string);
497 if (REQUEST_COMPLETED == lastbackstate) {
498 d_msg_backend(DEBUG_INFO,
499 " Native Installer recovery"
500 " is in REQUEST_COMPLETED \n");
502 ret = __native_recovery(lastbackstate);
504 d_msg_backend(DEBUG_INFO,
505 "Recovery of old instance failed errno: %d\n ",
507 d_msg_backend(DEBUG_RESULT, "%d\n", ret);
511 _error_no_to_string(ret, &errstr);
512 _broadcast_status_notification(pardata.ppkgname,
514 stat_cb(pardata.ppkgname, "error", errstr);
515 _broadcast_status_notification(pardata.ppkgname,
517 stat_cb(pardata.ppkgname, "end", "fail");
518 d_msg_backend(DEBUG_ERR,
519 "recovery failed with err(%d) (%s)\n",
522 d_msg_backend(DEBUG_INFO,
523 "recovery of last request success\n");
524 _broadcast_status_notification(pardata.ppkgname,
526 stat_cb(pardata.ppkgname, "end", "ok");
529 /* set the backend state as completed */
530 _set_backend_state(1);
533 * Another Instance may be running
536 ret = __is_another_instance_running(DEB);
539 if (pardata.ppkgname) {
540 _broadcast_status_notification
541 (pardata.ppkgname, "error",
542 "Another Instance Running");
543 stat_cb(pardata.ppkgname, "error",
544 "Another Instance Running");
545 _broadcast_status_notification
546 (pardata.ppkgname, "end", "fail");
547 stat_cb(pardata.ppkgname, "end",
550 _broadcast_status_notification(
553 "Another Instance Running");
554 stat_cb("unknown", "error",
555 "Another Instance Running");
556 _broadcast_status_notification(
560 stat_cb("unknown", "end", "fail");
562 d_msg_backend(DEBUG_INFO,
564 "Another Instance is running \n");
566 ret = NATIVEINSTALLER_ERR_RESOURCE_BUSY;
574 /* set the backend state as started */
575 _set_backend_state(0);
578 gptrpkgname = strdup(pardata.ppkgname);
580 /* Publish Notification that backend has started */
581 if (pardata.ppkgname)
582 _broadcast_status_notification(pardata.ppkgname, "start",
583 pardata.preq_cmd_string);
585 _broadcast_status_notification("unknown", "start",
586 pardata.preq_cmd_string);
589 _set_backend_state_info(REQUEST_ACCEPTED);
591 /* Set the input request info */
592 _save_last_input_info(pardata.ppkgname, pardata.reqcommand,
593 pardata.forceoverwrite);
595 switch (pardata.reqcommand) {
596 case INSTALL_BACKEND_CMD:
598 d_msg_backend(DEBUG_INFO, "[%s] --install %s\n",
599 "backend", pardata.ppkgname);
601 _broadcast_status_notification(pardata.ppkgname,
605 if (pardata.forceoverwrite == FORCE_OVERWITE) {
606 d_msg_backend(DEBUG_INFO,
607 "[%s] --install %s --force-overwrite\n",
608 "backend", pardata.ppkgname);
610 _pkgmgr_package_install(pardata.ppkgname,
612 "--force-overwrite");
614 d_msg_backend(DEBUG_INFO, "[%s] --install %s\n",
615 "backend", pardata.ppkgname);
617 _pkgmgr_package_install(pardata.ppkgname,
620 if (ret == NATIVEINSTALLER_ERR_NEED_USER_CONFIRMATION) {
623 else if (ret == NATIVEINSTALLER_SUCCESS) {
624 d_msg_backend(DEBUG_INFO, "install success\n");
625 _broadcast_status_notification(pardata.ppkgname,
627 stat_cb(pardata.ppkgname, "end", "ok");
632 _error_no_to_string(ret, &errstr);
633 _broadcast_status_notification(pardata.ppkgname,
635 stat_cb(pardata.ppkgname, "error", errstr);
636 _broadcast_status_notification(pardata.ppkgname,
639 stat_cb(pardata.ppkgname, "end", "fail");
640 d_msg_backend(DEBUG_ERR,
641 "install failed with err(%d) (%s)\n",
646 case REMOVE_BACKEND_CMD:
648 d_msg_backend(DEBUG_INFO, "[%s] uninstall %s\n",
649 "backend", pardata.ppkgname);
651 _broadcast_status_notification(pardata.ppkgname,
655 ret = __uninstall_package(pardata.ppkgname);
658 _error_no_to_string(ret, &errstr);
659 _broadcast_status_notification(pardata.ppkgname,
661 stat_cb(pardata.ppkgname, "error", errstr);
663 _broadcast_status_notification(pardata.ppkgname,
665 stat_cb(pardata.ppkgname, "end", "fail");
666 d_msg_backend(DEBUG_ERR,
667 "remove failed with err(%d) (%s)\n",
670 d_msg_backend(DEBUG_INFO, "remove success\n");
671 _broadcast_status_notification(pardata.ppkgname,
673 stat_cb(pardata.ppkgname, "end", "ok");
677 case CLEAR_BACKEND_CMD:
679 d_msg_backend(DEBUG_INFO, "[%s] clear data %s\n",
680 "backend", pardata.ppkgname);
682 _broadcast_status_notification(pardata.ppkgname,
686 ret = __clear_private_data(pardata.ppkgname);
689 _error_no_to_string(ret, &errstr);
690 _broadcast_status_notification(pardata.ppkgname,
692 stat_cb(pardata.ppkgname, "error", errstr);
693 _broadcast_status_notification(pardata.ppkgname,
695 stat_cb(pardata.ppkgname, "end", "fail");
696 d_msg_backend(DEBUG_ERR,
697 "clear data failed with err(%d) (%s)\n",
700 d_msg_backend(DEBUG_INFO, "clear data success\n");
701 _broadcast_status_notification(pardata.ppkgname,
703 stat_cb(pardata.ppkgname, "end", "ok");
709 _broadcast_status_notification("unknown", "command",
711 _broadcast_status_notification("unknown", "error",
713 stat_cb("unknown", "error", "not supported");
714 _broadcast_status_notification("unknown",
716 stat_cb("unknown", "end", "fail");
717 d_msg_backend(DEBUG_ERR, "unknown command \n");
719 ret = NATIVEINSTALLER_ERR_WRONG_PARAM;
727 if (_get_backend_state_info() != DPKG_REQUEST_PENDING) {
729 _set_backend_state_info(REQUEST_COMPLETED);
730 /* set the backend state as completed */
731 _set_backend_state(1);
732 d_msg_backend(DEBUG_RESULT, "%d\n", ret);