+/*
+ * rpm-installer
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>,
+ * Jaeho Lee <jaeho81.lee@samsung.com>, Shobhit Srivastava <shobhit.s@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+
+
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#define __USE_GNU
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <wait.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h> /* for isspace () */
+#include <time.h>
+#include <vconf.h>
+
+#include "native_installer_util.h"
+#include "nativeinstaller.h"
+
+#define INSTALL_SCRIPT "/usr/bin/install_spk.sh"
+#define UNINSTALL_SCRIPT "/usr/bin/uninstall_spk.sh"
+#define UPDATE_PKG_SCRIPT "/usr/bin/update_avail_spk.sh"
+#define AUDIT_SCRIPT "/usr/bin/audit_spk_sh"
+
+typedef enum __dpkg_request_type {
+ INSTALL_REQ,
+ UNINSTALL_REQ,
+ AUDIT_REQ,
+ UPGRADE_REQ,
+ UPDATE_CONTROL_REQ,
+} dpkg_request_type;
+
+typedef enum __dpkgaction {
+ DPKGNONE,
+ DPKGINSTALL,
+ DPKGCONFIGURE,
+ DPKGUNINSTALL,
+ DPKGPURGE,
+ DPKGUPGRADE,
+ DPKGUNKNOWN,
+ DPKGMAXOPR
+} dpkgaction;
+
+typedef struct __operationsinfo {
+ dpkgaction action;
+ int lastactivity;
+ int totalactivity;
+ struct __operationsinfo *nextoperations;
+} operationsinfo;
+
+typedef struct __dpkgoperations {
+ dpkg_request_type requesttype;
+ dpkgaction runningoperations;
+ operationsinfo *operationshead;
+ int totaloperations;
+ int currentprogress;
+ int percentageprogress;
+} dpkgoperations;
+
+
+dpkgoperations dpkgrequestedoperations;
+static int is_operations_cleaned;
+extern char *gptrpkgname;
+
+static char *__make_notification_string(dpkg_request_type request_type,
+ char *status,
+ char *msg);
+static int __map_dpkg_operation_to_enum(char *action);
+static int __native_installer_init_operations(dpkg_request_type requesttype);
+static int __pkgmgr_dpkg_xsystem(dpkg_request_type requesttype,
+ const char *argv[]);
+static void __native_installer_clean_operations();
+static void __dpkg_process_status(char *pkgqstate);
+static void __perform_dpkg_status_fd_read(int fd);
+static void __dpkg_process_action(char *action);
+static void __process_dpkg_status_line(char *line);
+extern char evt_notification[64];
+
+static char *__make_notification_string(dpkg_request_type request_type,
+ char *status,
+ char *msg)
+{
+ char requeststr[16];
+ char *statusstring = NULL;
+ int len = strlen(status) + strlen(msg);
+ len = len + 16;
+ statusstring = (char *)malloc(len);
+ if (PM_UNLIKELY(statusstring == NULL)) {
+ d_msg_backend(DEBUG_ERR, "Malloc Failed\n");
+ return NULL;
+ }
+ switch (request_type) {
+ case INSTALL_REQ:
+ snprintf(requeststr, sizeof(requeststr), "Install");
+ break;
+ case UNINSTALL_REQ:
+ snprintf(requeststr, sizeof(requeststr), "Remove");
+ break;
+ case AUDIT_REQ:
+ snprintf(requeststr, sizeof(requeststr), "Audit");
+ break;
+ case UPGRADE_REQ:
+ snprintf(requeststr, sizeof(requeststr), "Update");
+ break;
+ default:
+ snprintf(requeststr, sizeof(requeststr), "default");
+ break;
+ }
+
+ snprintf(statusstring, len, "%s\t%s\t%s", requeststr, status, msg);
+ return statusstring;
+
+}
+
+static int __map_dpkg_operation_to_enum(char *action)
+{
+ if (strncmp(action, "install", strlen("install")) == 0)
+ return DPKGINSTALL;
+ else if (strncmp(action, "configure", strlen("configure")) == 0)
+ return DPKGCONFIGURE;
+ else if (strncmp(action, "purge", strlen("purge")) == 0)
+ return DPKGPURGE;
+ else if (strncmp(action, "remove", strlen("remove")) == 0)
+ return DPKGUNINSTALL;
+ else if (strncmp(action, "upgrade", strlen("upgrade")) == 0)
+ return DPKGUPGRADE;
+ else
+ return DPKGUNKNOWN;
+}
+
+static void __native_installer_clean_operations()
+{
+ operationsinfo *ptemp = dpkgrequestedoperations.operationshead;
+ operationsinfo *ptempnext;
+ while (ptemp != NULL) {
+ ptempnext = ptemp->nextoperations;
+ free(ptemp);
+ ptemp = ptempnext;
+ }
+ dpkgrequestedoperations.operationshead = NULL;
+}
+
+/* This function will be called when status message
+received by installer from dpkg */
+
+static void __dpkg_process_status(char *pkgqstate)
+{
+ /* status: <pkg>: <pkg qstate> */
+ int increment = 0;
+ int increamentactivity = 0;
+ int expectedpercentage = 0;
+
+ d_msg_backend(DEBUG_INFO, "__dpkg_process_status :: %s \n", pkgqstate);
+ d_msg_backend(DEBUG_INFO,
+ "__dpkg_process_status current request type:: %d Current running Operations = %d \n",
+ dpkgrequestedoperations.requesttype,
+ dpkgrequestedoperations.runningoperations);
+ switch (dpkgrequestedoperations.requesttype) {
+ case INSTALL_REQ:
+ {
+ switch (dpkgrequestedoperations.runningoperations) {
+ case DPKGINSTALL:
+ {
+ operationsinfo *pinstall =
+ dpkgrequestedoperations.operationshead;
+ if (pinstall == NULL)
+ goto RETURN;
+
+ if (pinstall->action != DPKGINSTALL)
+ goto RETURN;
+
+ if (strncmp(pkgqstate, "half-installed",
+ strlen("half-installed")) == 0) {
+ if (pinstall->lastactivity == 1) {
+ /* got "half-installed" repeated times */
+ increment = 5;
+ } else if (pinstall->lastactivity == 0) {
+ /* got "half-installed" first times */
+ pinstall->lastactivity = 1;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ } else
+ if (strncmp(pkgqstate, "unpacked",
+ strlen("unpacked")) == 0) {
+ if (pinstall->lastactivity == 2) {
+ /* got "unpacked" repeated times */
+ increment = 5;
+ } else if (pinstall->lastactivity == 1) {
+ /* got "unpacked" first times */
+ pinstall->lastactivity =
+ 2;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ }
+ break;
+ }
+
+ case DPKGCONFIGURE:
+ {
+ operationsinfo *pconfigure =
+ dpkgrequestedoperations.operationshead;
+ if (pconfigure == NULL)
+ goto RETURN;
+
+ if (pconfigure->action != DPKGCONFIGURE)
+ goto RETURN;
+ if (strncmp(pkgqstate, "unpacked",
+ strlen("unpacked")) == 0) {
+ if (pconfigure->lastactivity == 1) {
+ /* got "unpacked" repeated times */
+ increment = 5;
+ } else if (pconfigure->lastactivity == 0) {
+ /* got "unpacked" first times */
+ pconfigure->lastactivity = 1;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ } else if (strncmp(pkgqstate, "half-configured",
+ strlen("half-configured")) == 0) {
+ if (pconfigure->lastactivity == 2) {
+ /* got "half-configured" repeated times */
+ increment = 5;
+ } else if (pconfigure->lastactivity == 1) {
+ /* got "half-configured" first times */
+ pconfigure->lastactivity = 2;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ } else if (strncmp(pkgqstate, "installed",
+ strlen("installed")) == 0) {
+ increamentactivity = 1;
+ dpkgrequestedoperations.percentageprogress = 100;
+ increment = 0;
+ dpkgrequestedoperations.operationshead =
+ pconfigure->nextoperations;
+ if (pconfigure)
+ free(pconfigure);
+ }
+ break;
+ }
+ default:
+ break;
+
+ }
+ if (strncmp(pkgqstate, "installed", strlen("installed")) == 0) {
+ increamentactivity = 0;
+ dpkgrequestedoperations.percentageprogress = 100;
+ increment = 0;
+ }
+ break;
+ }
+
+ case UNINSTALL_REQ:
+ {
+ switch (dpkgrequestedoperations.runningoperations) {
+ case DPKGUNINSTALL:
+ {
+ operationsinfo *ptemp =
+ dpkgrequestedoperations.operationshead;
+ if (!ptemp)
+ goto RETURN;
+
+ if (ptemp->action != DPKGUNINSTALL)
+ goto RETURN;
+
+ if (strncmp(pkgqstate, "half-configured",
+ strlen("half-configured")) == 0) {
+ if (ptemp->lastactivity == 1) {
+ /* got "half-configured" repeated times */
+ increment = 5;
+ } else if (ptemp->lastactivity == 0) {
+ /* got "half-configured" first times */
+ ptemp->lastactivity = 1;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ } else
+ if (strncmp(pkgqstate, "half-installed",
+ strlen("half-installed")) == 0) {
+ if (ptemp->lastactivity == 2) {
+ /* got "half-installed" repeated times */
+ increment = 5;
+ } else if (ptemp->lastactivity == 1) {
+ /* got "half-installed" first times */
+ ptemp->lastactivity = 2;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ } else if (strncmp(pkgqstate, "config-files",
+ strlen("config-files")) == 0) {
+ if (ptemp->lastactivity == 3) {
+ /* got "config-files" repeated times */
+ increment = 5;
+ } else if (ptemp->lastactivity == 2) {
+ /* got "config-files" first times */
+ ptemp->lastactivity = 3;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ } else if (strncmp(pkgqstate, "not-installed",
+ strlen("not-installed")) == 0) {
+ increamentactivity = 1;
+ dpkgrequestedoperations.percentageprogress = 100;
+ increment = 0;
+ dpkgrequestedoperations.operationshead =
+ ptemp->nextoperations;
+ if (ptemp)
+ free(ptemp);
+ }
+ break;
+ }
+
+ default:
+ break;
+
+ }
+ if (strncmp
+ (pkgqstate, "not-installed",
+ strlen("not-installed")) == 0) {
+ increamentactivity = 0;
+ dpkgrequestedoperations.percentageprogress = 100;
+ increment = 0;
+ }
+ break;
+ }
+
+ case UPGRADE_REQ:
+ {
+ switch (dpkgrequestedoperations.runningoperations) {
+ case DPKGUPGRADE:
+ {
+ operationsinfo *pupgrade =
+ dpkgrequestedoperations.
+ operationshead;
+ /*d_msg_backend(DEBUG_INFO, "DpkgProcessStatus ::
+ Inside DPKGUPGRADE %s \n", pkgqstate); */
+ if (pupgrade == NULL)
+ goto RETURN;
+ if (pupgrade->action != DPKGUPGRADE)
+ goto RETURN;
+
+ if (strncmp(pkgqstate, "half-configured",
+ strlen("half-configured")) == 0) {
+ if (pupgrade->lastactivity == 1) {
+ /* got "half-configured" repeated times */
+ increment = 5;
+ } else if (pupgrade->lastactivity == 0) {
+ /* got "half-configured" first times */
+ pupgrade->lastactivity =
+ 1;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ } else if (strncmp(pkgqstate, "unpacked",
+ strlen("unpacked")) == 0) {
+ if (pupgrade->lastactivity == 2) {
+ /* got "unpacked" repeated times */
+ increment = 5;
+ } else if (pupgrade->lastactivity == 1) {
+ /* got "unpacked" first times */
+ pupgrade->lastactivity =
+ 2;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ } else if (strncmp(pkgqstate, "half-installed",
+ strlen("half-installed")) == 0) {
+ if (pupgrade->lastactivity
+ == 3) {
+ /* got "half-installed" repeated times */
+ increment = 5;
+ } else if (pupgrade->lastactivity == 2) {
+ /* got "half-installed" first times */
+ pupgrade->lastactivity
+ = 3;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ } else if (strncmp(pkgqstate, "unpacked",
+ strlen("unpacked")) == 0) {
+ if (pupgrade->lastactivity == 4) {
+ /* got "unpacked" repeated times */
+ increment = 5;
+ } else if (pupgrade->lastactivity == 3) {
+ /* got "unpacked" first times */
+ pupgrade->lastactivity
+ = 4;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ }
+ break;
+ }
+
+ case DPKGCONFIGURE:
+ {
+ operationsinfo *pconfigure =
+ dpkgrequestedoperations.operationshead;
+ /*d_msg_backend(DEBUG_INFO, "DpkgProcessStatus ::
+ Inside DPKGCONFIGURE %s \n", pkgqstate); */
+ if (pconfigure == NULL)
+ goto RETURN;
+
+ if (pconfigure->action != DPKGCONFIGURE)
+ goto RETURN;
+ if (strncmp(pkgqstate, "unpacked",
+ strlen("unpacked")) == 0) {
+ if (pconfigure->lastactivity == 1) {
+ /* got "unpacked" repeated times */
+ increment = 5;
+ } else if (pconfigure->lastactivity == 0) {
+ /* got "unpacked" first times */
+ pconfigure->lastactivity
+ = 1;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ } else if (strncmp(pkgqstate, "half-configured",
+ strlen("half-configured")) == 0) {
+ if (pconfigure->lastactivity == 2) {
+ /* got "half-configured" repeated times */
+ increment = 5;
+ } else if (pconfigure->lastactivity == 1) {
+ /* got "half-configured" first times */
+ pconfigure->lastactivity
+ = 2;
+ increamentactivity = 1;
+ increment = 0;
+ }
+ } else if (strncmp(pkgqstate, "installed",
+ strlen("installed")) == 0) {
+ increamentactivity = 1;
+ dpkgrequestedoperations.percentageprogress = 100;
+ increment = 0;
+ dpkgrequestedoperations.operationshead =
+ pconfigure->nextoperations;
+ if (pconfigure)
+ free(pconfigure);
+ }
+ break;
+ }
+ default:
+ d_msg_backend(DEBUG_ERR,
+ "__dpkg_process_status ::"
+ " Inside default %s \n",
+ pkgqstate);
+ break;
+
+ }
+ if (strncmp(pkgqstate, "installed",
+ strlen("installed")) == 0) {
+ increamentactivity = 0;
+ dpkgrequestedoperations.percentageprogress = 100;
+ increment = 0;
+ }
+ break;
+ }
+ default:
+ break;
+
+ }
+
+ if (increamentactivity == 1) {
+ dpkgrequestedoperations.currentprogress += 1;
+ if (dpkgrequestedoperations.currentprogress >
+ dpkgrequestedoperations.totaloperations)
+ dpkgrequestedoperations.currentprogress =
+ dpkgrequestedoperations.totaloperations;
+ }
+
+ expectedpercentage =
+ (dpkgrequestedoperations.currentprogress * 100) /
+ dpkgrequestedoperations.totaloperations;
+ if (dpkgrequestedoperations.percentageprogress < expectedpercentage)
+ dpkgrequestedoperations.percentageprogress = expectedpercentage;
+ else
+ dpkgrequestedoperations.percentageprogress += increment;
+
+ if (dpkgrequestedoperations.percentageprogress == 100) {
+ operationsinfo *ptemp = dpkgrequestedoperations.operationshead;
+ operationsinfo *ptempnext;
+ while (ptemp != NULL) {
+ ptempnext = ptemp->nextoperations;
+ free(ptemp);
+ ptemp = ptempnext;
+ }
+ dpkgrequestedoperations.operationshead = NULL;
+ }
+ return;
+RETURN:
+ d_msg_backend(DEBUG_ERR, "__dpkg_process_status :: Error Happened \n");
+ return;
+
+}
+
+static void __dpkg_process_action(char *action)
+{
+ /* This function will be called when */
+ dpkgaction currentaction = DPKGUNKNOWN;
+
+ currentaction = __map_dpkg_operation_to_enum(action);
+
+ if (currentaction <= DPKGNONE || currentaction >= DPKGUNKNOWN)
+ return;
+
+ d_msg_backend(DEBUG_INFO, "__dpkg_process_action :: %s = %d \n", action,
+ currentaction);
+ d_msg_backend(DEBUG_INFO,
+ "__dpkg_process_action current request type::"
+ " %d Current running Operations = %d \n",
+ dpkgrequestedoperations.requesttype,
+ dpkgrequestedoperations.runningoperations);
+ switch (dpkgrequestedoperations.requesttype) {
+ case INSTALL_REQ:
+ {
+ switch (currentaction) {
+ case DPKGINSTALL:
+ {
+ switch (dpkgrequestedoperations.runningoperations) {
+ case DPKGNONE:
+ {
+ dpkgrequestedoperations.runningoperations =
+ DPKGINSTALL;
+
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+
+ case DPKGCONFIGURE:
+ {
+ switch (dpkgrequestedoperations.runningoperations) {
+ case DPKGINSTALL:
+ {
+ operationsinfo *ptemp =
+ dpkgrequestedoperations.operationshead;
+ dpkgrequestedoperations.operationshead =
+ ptemp->nextoperations;
+ free(ptemp);
+
+ dpkgrequestedoperations.runningoperations =
+ DPKGCONFIGURE;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+
+ case UNINSTALL_REQ:
+ {
+ switch (currentaction) {
+ case DPKGUNINSTALL:
+ {
+ switch (dpkgrequestedoperations.runningoperations) {
+ case DPKGNONE:
+ {
+ dpkgrequestedoperations.runningoperations =
+ DPKGUNINSTALL;
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case UPGRADE_REQ:
+ {
+ switch (currentaction) {
+ case DPKGUPGRADE:
+ {
+ switch (dpkgrequestedoperations.runningoperations) {
+ case DPKGNONE:
+ {
+ dpkgrequestedoperations.runningoperations =
+ DPKGUPGRADE;
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+
+ case DPKGCONFIGURE:
+ {
+ switch
+ (dpkgrequestedoperations.runningoperations) {
+ case DPKGUPGRADE:
+ {
+ operationsinfo *ptemp =
+ dpkgrequestedoperations.operationshead;
+ dpkgrequestedoperations.operationshead =
+ ptemp->nextoperations;
+ free(ptemp);
+
+ dpkgrequestedoperations.runningoperations =
+ DPKGCONFIGURE;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+
+ }
+}
+
+/**
+ dpkg sends strings like this:
+ 'status: <pkg>: <pkg qstate>'
+ errors look like this:
+ 'status: /var/cache/apt/archives/krecipes_0.8.1-0ubuntu1_i386.deb
+ : error : trying to overwrite
+ `/usr/share/doc/kde/HTML/en/krecipes/krectip.png',
+ which is also in package krecipes-data
+ and conffile-prompt like this
+ 'status: conffile-prompt: conffile : 'current-conffile' 'new-conffile'
+ useredited distedited
+
+ Newer versions of dpkg sent also:
+ 'processing: install: pkg'
+ 'processing: configure: pkg'
+ 'processing: remove: pkg'
+ 'processing: trigproc: trigger'
+ 'processing: upgrade: pkg'
+
+*/
+
+static void __process_dpkg_status_line(char *line)
+{
+ /* the status we output */
+ int value = 0;
+ char valuestr[4];
+ char status[256];
+ /*char *notification = NULL; */
+ int len;
+ char *tok[6];
+ if (line == NULL)
+ return;
+ d_msg_backend(DEBUG_INFO, "%s\n", line);
+
+ if (is_operations_cleaned == 1) {
+ d_msg_backend(DEBUG_ERR,
+ "ignoring status: Operations Cancelled \n");
+ return;
+ }
+ _tok_split_string(':', line, tok, sizeof(tok) / sizeof(tok[0]));
+ if (tok[0] == NULL || tok[1] == NULL || tok[2] == NULL) {
+ d_msg_backend(DEBUG_ERR, "ignoring line: not enough ':' \n");
+ return;
+ }
+ char *action = tok[2];
+
+ /* 'processing' from dpkg looks like */
+ /* 'processing: <action>: package */
+ if (strncmp(tok[0], "processing", strlen("processing")) == 0) {
+ action = tok[1];
+ __dpkg_process_action(action);
+
+ value = dpkgrequestedoperations.percentageprogress;
+ snprintf(valuestr, 4, "%d", value);
+ _broadcast_status_notification(tok[2], "install_percent",
+ valuestr);
+ stat_cb(tok[2], "install_percent", valuestr);
+ len = snprintf(status, sizeof(status), "status: %s: %d\n",
+ tok[2], value);
+ d_msg_backend(DEBUG_INFO, "%s", status);
+ return;
+ }
+
+ if (strncmp(action, "error", strlen("error")) == 0) {
+
+ /* sometimes there is ":" in the error string so that
+ the error message is split between tok[3] and tok[4],
+ concat them again */
+ if (tok[4] != NULL)
+ tok[3][strlen(tok[3])] = ':';
+
+ snprintf(valuestr, 4, "%d", value);
+ _broadcast_status_notification(tok[1], "error", tok[3]);
+ stat_cb(tok[1], "error", tok[3]);
+ /*sleep(1); */
+ len = snprintf(status, sizeof(status), "error: %s: %s\n",
+ tok[1], tok[3]);
+ d_msg_backend(DEBUG_INFO, "%s", status);
+ __native_installer_clean_operations();
+ is_operations_cleaned = 1;
+ return;
+ }
+ /* status: conffile-prompt: conffile : 'current-conffile'
+ 'new-conffile' useredited distedited */
+ if (strncmp(action, "conffile", strlen("conffile")) == 0) {
+ value += 10;
+ snprintf(valuestr, 4, "%d", value);
+ _broadcast_status_notification(tok[1], "install_percent",
+ valuestr);
+ stat_cb(tok[1], "install_percent", valuestr);
+ /*sleep(1); */
+ len = snprintf(status, sizeof(status), "status: %s: %d\n",
+ tok[1], value);
+ d_msg_backend(DEBUG_INFO, "%s", status);
+ return;
+ }
+
+ /* status: <pkg>: <pkg qstate> */
+ if (strncmp(tok[0], "status", strlen("status")) == 0) {
+ __dpkg_process_status(tok[2]);
+ value = dpkgrequestedoperations.percentageprogress;
+ snprintf(valuestr, 4, "%d", value);
+ _broadcast_status_notification(tok[1], "install_percent",
+ valuestr);
+ stat_cb(tok[1], "install_percent", valuestr);
+ /*sleep(1); */
+ len = snprintf(status, sizeof(status), "status: %s: %d\n",
+ tok[1], value);
+ d_msg_backend(DEBUG_INFO, "%s", status);
+ return;
+ }
+
+ len = snprintf(status, sizeof(status),
+ "(parsed from dpkg) pkg: %s action: %s\n", tok[1],
+ action);
+ d_msg_backend(DEBUG_INFO, "%s", status);
+}
+
+static void __perform_dpkg_status_fd_read(int fd)
+{
+ char *buf_ptr = NULL;
+ char *tmp_ptr = NULL;
+ int size = 0;
+ static char buffer[1024] = {0,};
+ static int buffer_position;
+
+ size = read(fd, &buffer[buffer_position],
+ sizeof(buffer) - buffer_position);
+ buffer_position += size;
+ if (size <= 0)
+ return;
+
+ /* Process each line of the recieved buffer */
+ buf_ptr = tmp_ptr = buffer;
+ while ((tmp_ptr = (char *)memchr(buf_ptr, '\n',
+ buffer + buffer_position - buf_ptr)) != NULL) {
+ *tmp_ptr = 0;
+ __process_dpkg_status_line(buf_ptr);
+ /* move to next line and continue*/
+ buf_ptr = tmp_ptr + 1;
+ }
+
+ /*move the remaining bits at the start of the buffer
+ and update the buffer position */
+ buf_ptr = (char *)memrchr(buffer, 0, buffer_position);
+ if (buf_ptr == NULL)
+ return;
+
+ /* we have processed till the last \n which has now become
+ 0x0. So we increase the pointer to next position*/
+ buf_ptr++;
+
+ memmove(buffer, buf_ptr, buf_ptr - buffer);
+ buffer_position = buffer + buffer_position - buf_ptr;
+}
+
+static int __native_installer_init_operations(dpkg_request_type requesttype)
+{
+ operationsinfo *pHead = NULL;
+ int totaloperations = 0;
+
+ switch (requesttype) {
+ case INSTALL_REQ:
+ {
+ /*
+ processing: install: <pkg>
+ status: <pkg>: half-installed
+ status: <pkg>: unpacked
+ status: <pkg>: unpacked
+ processing: configure: <pkg>
+ status: <pkg>: unpacked
+ status: <pkg>: half-configured
+ status: <pkg>: installed
+
+ */
+
+ operationsinfo *pinstall = NULL, *pconfigure = NULL;
+ pinstall =
+ (operationsinfo *) malloc(sizeof(operationsinfo));
+ pconfigure =
+ (operationsinfo *) malloc(sizeof(operationsinfo));
+ if (!pinstall || !pconfigure) {
+ if (pinstall)
+ free(pinstall);
+ if (pconfigure)
+ free(pconfigure);
+ goto ERROR;
+ }
+ /* install operations */
+ pinstall->action = DPKGINSTALL;
+ pinstall->lastactivity = 0;
+ pinstall->totalactivity = 2;
+ pinstall->nextoperations = pconfigure;
+
+ /* configure operations */
+ pconfigure->action = DPKGCONFIGURE;
+ pconfigure->lastactivity = 0;
+ pconfigure->totalactivity = 3;
+ pconfigure->nextoperations = NULL;
+
+ pHead = pinstall;
+
+ totaloperations =
+ pinstall->totalactivity + pconfigure->totalactivity;
+ if (totaloperations == 0) {
+ if (pinstall)
+ free(pinstall);
+ if (pconfigure)
+ free(pconfigure);
+ goto ERROR;
+ }
+ break;
+ }
+ case UNINSTALL_REQ:
+ {
+ /*
+ processing: remove: <pkg>
+ status: <pkg>: half-configured
+ status: <pkg>: half-installed
+ status: <pkg>: config-files
+ status: <pkg>: config-files
+ status: <pkg>: config-files
+ status: <pkg>: not-installed
+ */
+
+ operationsinfo *pUnInstall = NULL;
+ pUnInstall =
+ (operationsinfo *) malloc(sizeof(operationsinfo));
+ if (!pUnInstall) {
+ goto ERROR;
+ }
+ /* UNINSTALL_REQ operations */
+ pUnInstall->action = DPKGUNINSTALL;
+ pUnInstall->lastactivity = 0;
+ pUnInstall->totalactivity = 4;
+ pUnInstall->nextoperations = NULL;
+
+ pHead = pUnInstall;
+
+ totaloperations = pUnInstall->totalactivity;
+ if (totaloperations == 0) {
+ if (pUnInstall)
+ free(pUnInstall);
+ goto ERROR;
+ }
+ break;
+ }
+
+ case UPGRADE_REQ:
+ {
+ /*
+ processing: upgrade: <pkg>
+ status: <pkg>: half-configured
+ status: <pkg>: unpacked
+ status: <pkg>: half-installed
+ status: <pkg>: unpacked
+ status: <pkg>: unpacked
+ processing: configure: <pkg>
+ status: <pkg>: unpacked
+ status: <pkg>: unpacked
+ status: <pkg>: half-configured
+ status: <pkg>: installed
+
+ */
+ operationsinfo *pupgrade = NULL;
+ operationsinfo *pconfigure = NULL;
+ pupgrade =
+ (operationsinfo *) malloc(sizeof(operationsinfo));
+ pconfigure =
+ (operationsinfo *) malloc(sizeof(operationsinfo));
+ if (!pupgrade || !pconfigure) {
+ if (pupgrade)
+ free(pupgrade);
+ if (pconfigure)
+ free(pconfigure);
+ goto ERROR;
+ }
+ /* install operations */
+ pupgrade->action = DPKGUPGRADE;
+ pupgrade->lastactivity = 0;
+ pupgrade->totalactivity = 4;
+ pupgrade->nextoperations = pconfigure;
+
+ /* configure operations */
+ pconfigure->action = DPKGCONFIGURE;
+ pconfigure->lastactivity = 0;
+ pconfigure->totalactivity = 3;
+ pconfigure->nextoperations = NULL;
+
+ pHead = pupgrade;
+
+ totaloperations =
+ pupgrade->totalactivity + pconfigure->totalactivity;
+ if (totaloperations == 0) {
+ if (pupgrade)
+ free(pupgrade);
+ if (pconfigure)
+ free(pconfigure);
+ goto ERROR;
+ }
+ break;
+ }
+
+ default:
+ break;
+
+ }
+
+ dpkgrequestedoperations.requesttype = requesttype;
+ dpkgrequestedoperations.operationshead = pHead;
+ dpkgrequestedoperations.runningoperations = DPKGNONE;
+ dpkgrequestedoperations.currentprogress = 0;
+ dpkgrequestedoperations.percentageprogress = 0;
+ dpkgrequestedoperations.totaloperations = totaloperations;
+ is_operations_cleaned = 0;
+ return 0;
+ ERROR:
+ d_msg_backend(DEBUG_ERR, "__native_installer_init_operations"
+ " :: Failed \n");
+ return -1;
+}
+
+static int __pkgmgr_dpkg_xsystem(dpkg_request_type requesttype,
+ const char *argv[])
+{
+ sigset_t sigmask;
+ sigset_t original_sigmask;
+ int err = 0;
+ int n = 0;
+ char statusfd[32];
+ int fd[2];
+ int status;
+ pid_t pid;
+ const char *Args[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+
+ if (__native_installer_init_operations(requesttype) == -1) {
+ d_msg_backend(DEBUG_ERR,
+ "_pkgmgr_dpkg_install_pkg::"
+ " __native_installer_init_operations failed ",
+ err);
+ return -1;
+ }
+
+ while (argv[n] != NULL) {
+ /*d_msg_backend(DEBUG_INFO, "%s\t", argv[n] ); */
+ Args[n] = argv[n];
+ n++;
+ }
+ err = pipe(fd);
+ if (err != 0) {
+ d_msg_backend(DEBUG_ERR,
+ "_pkgmgr_dpkg_install_pkg:: status Pipe creation failed ",
+ err);
+ } else {
+ snprintf(statusfd, 32, "%d", fd[1]);
+ Args[n++] = "--status-fd";
+ Args[n++] = statusfd;
+ }
+
+ /* Mask off sig int/quit. We do this because dpkg also does when
+ it forks scripts. What happens is that when you hit ctrl-c it sends
+ it to all processes in the group. Since dpkg ignores the signal
+ it doesn't die but we do! So we must also ignore it */
+ __sighandler_t old_SIGQUIT = signal(SIGQUIT, SIG_IGN);
+ __sighandler_t old_SIGINT = signal(SIGINT, SIG_IGN);
+
+ /* ignore SIGHUP as well (debian #463030) */
+ __sighandler_t old_SIGHUP = signal(SIGHUP, SIG_IGN);
+
+ pid = vfork();
+
+ switch (pid) {
+ case -1:
+ perror("fork failed");
+ return -1;
+ case 0:
+ /* child */
+ {
+ close(fd[0]);
+ if (execvp(argv[0], (char *const *)Args) == -1) {
+ perror("execvp");
+ }
+ _exit(100);
+ }
+ default:
+ /* parent */
+ break;
+ }
+
+ close(fd[1]);
+ /* setups fds */
+ sigemptyset(&sigmask);
+ sigprocmask(SIG_BLOCK, &sigmask, &original_sigmask);
+
+ while ((err = waitpid(pid, &status, WNOHANG)) != pid) {
+ if (err < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("waitpid");
+ /* Restore sig int/quit */
+ signal(SIGQUIT, old_SIGQUIT);
+ signal(SIGINT, old_SIGINT);
+ signal(SIGHUP, old_SIGHUP);
+ close(fd[0]);
+ return -1;
+ }
+ /* read the status using status fd */
+ int select_ret;
+ fd_set rfds;
+ struct timespec tv;
+ FD_ZERO(&rfds);
+ /*FD_SET(0, &rfds); */
+ FD_SET(fd[0], &rfds);
+ tv.tv_sec = 1;
+ tv.tv_nsec = 0;
+ select_ret =
+ pselect(fd[0] + 1, &rfds, NULL, NULL, &tv,
+ &original_sigmask);
+ if (select_ret == 0)
+ continue;
+
+ else if (select_ret < 0 && errno == EINTR)
+ continue;
+ else if (select_ret < 0) {
+ perror("select() returned error");
+ continue;
+ }
+ if (FD_ISSET(fd[0], &rfds))
+ __perform_dpkg_status_fd_read(fd[0]);
+ }
+ close(fd[0]);
+
+ /* Restore sig int/quit */
+ signal(SIGQUIT, old_SIGQUIT);
+ signal(SIGINT, old_SIGINT);
+ signal(SIGHUP, old_SIGHUP);
+
+ /* Check for an error code. */
+ if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0) {
+ /* if it was set to "keep-dpkg-runing" then we won't return */
+ /* here but keep the loop going and just report it as a error */
+ /* for later */
+
+ if (WIFSIGNALED(status) != 0 && WTERMSIG(status) == SIGSEGV) {
+ d_msg_backend(DEBUG_INFO,
+ "Sub-process %s received a segmentation fault. \n",
+ Args[0]);
+ } else if (WIFEXITED(status) != 0) {
+ d_msg_backend(DEBUG_INFO,
+ "Sub-process %s returned an error code (%u)\n",
+ Args[0], WEXITSTATUS(status));
+ } else {
+ d_msg_backend(DEBUG_INFO,
+ "Sub-process %s exited unexpectedly\n",
+ Args[0]);
+ }
+ }
+ return WEXITSTATUS(status);
+}
+
+int _pkgmgr_dpkg_uninstall_pkg(char *pkgname)
+{
+ int ret = 0;
+ int err = 0;
+ char buff[256] = {'\0'};
+ ret = _unset_event_notification();
+ if (ret < 0) {
+ d_msg_backend(DEBUG_ERR, "_unset_event_notification failed\n");
+ }
+ const char *argv[] = { UNINSTALL_SCRIPT, pkgname, NULL };
+ ret = __pkgmgr_dpkg_xsystem(UNINSTALL_REQ, argv);
+ if (ret != 0) {
+ d_msg_backend(DEBUG_ERR, "uninstall failed with error(%d)\n",
+ ret);
+ return ret;
+ }
+ /* Uninstallation Success. Remove the installation time key from vconf*/
+ snprintf(buff, 256, "db/app-info/%s/installed-time", gptrpkgname);
+ err= vconf_unset(buff);
+ if (err) {
+ d_msg_backend(DEBUG_ERR, "unset installation time failed\n");
+ }
+ return ret;
+}
+
+int _pkgmgr_dpkg_install_pkg(char *pkgfilepath, char *installoptions)
+{
+ int err = 0;
+ int ret = 0;
+ int value = 0;
+ time_t cur_time;
+ char buff[256] = {'\0'};
+ const char *argv[] = {
+ INSTALL_SCRIPT, pkgfilepath, installoptions, NULL
+ };
+ if (!strncmp(evt_notification, "True", strlen("True"))
+ || !strncmp(evt_notification, "False", strlen("False"))) {
+ if (!strncmp(evt_notification, "True", strlen("True")))
+ value = 1;
+ else
+ value = 0;
+
+ err = _set_event_notification(value);
+ if (err < 0) {
+ d_msg_backend(DEBUG_ERR,
+ "_set_event_notification failed\n");
+ /* TODO : handle error */
+ }
+ }
+ err = __pkgmgr_dpkg_xsystem(INSTALL_REQ, argv);
+ if (err != 0) {
+ d_msg_backend(DEBUG_ERR, "install complete with error(%d)\n",
+ err);
+ return err;
+ }
+ /* Install Success. Store the installation time*/
+ cur_time = time(NULL);
+ snprintf(buff, 256, "db/app-info/%s/installed-time", gptrpkgname);
+ /* The time is stored in time_t format. It can be converted to
+ local time or GMT time as per the need by the apps*/
+ ret = vconf_set_int(buff, cur_time);
+ if(ret) {
+ d_msg_backend(DEBUG_ERR, "setting installation time failed\n");
+ vconf_unset(buff);
+ }
+ return err;
+}
+
+int _pkgmgr_dpkg_upgrade_pkg(char *pkgfilepath, char *installoptions)
+{
+ int err = 0;
+ int value = 0;
+ int ret = 0;
+ time_t cur_time;
+ char buff[256] = {'\0'};
+ if (!strncmp(evt_notification, "True", strlen("True")) ||
+ !strncmp(evt_notification, "False", strlen("False"))) {
+ if (!strncmp(evt_notification, "True", strlen("True")))
+ value = 1;
+ else
+ value = 0;
+
+ err = _set_event_notification(value);
+ if (err < 0) {
+ d_msg_backend(DEBUG_ERR,
+ "_set_event_notification failed\n");
+ /* TODO : handle error */
+ }
+ }
+ const char *argv[] = {
+ INSTALL_SCRIPT, pkgfilepath, installoptions, NULL
+ };
+ err = __pkgmgr_dpkg_xsystem(UPGRADE_REQ, argv);
+ if (err != 0) {
+ d_msg_backend(DEBUG_ERR, "install complete with error(%d)\n",
+ err);
+ return err;
+ }
+ /* Upgrade Success. Store the upgradation time*/
+ cur_time = time(NULL);
+ snprintf(buff, 256, "db/app-info/%s/installed-time", gptrpkgname);
+ /* The time is stored in time_t format. It can be converted to
+ local time or GMT time as per the need by the apps*/
+ ret = vconf_set_int(buff, cur_time);
+ if(ret) {
+ d_msg_backend(DEBUG_ERR, "setting upgradation time failed\n");
+ }
+ return err;
+}
+