summaryrefslogtreecommitdiff
path: root/src/ui/popup-runner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/popup-runner.cpp')
-rw-r--r--src/ui/popup-runner.cpp301
1 files changed, 301 insertions, 0 deletions
diff --git a/src/ui/popup-runner.cpp b/src/ui/popup-runner.cpp
new file mode 100644
index 0000000..6411558
--- /dev/null
+++ b/src/ui/popup-runner.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+/*
+ * @file popup-runner.cpp
+ * @author Janusz Kozerski (j.kozerski@samsung.com)
+ * @version 1.0
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <iostream>
+#include <sstream>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <cchecker/app.h>
+#include <cchecker/logic.h>
+#include <cchecker/log.h>
+#include <cchecker/UIBackend.h>
+#include <cchecker/popup-runner.h>
+
+namespace { // anonymous
+
+using namespace CCHECKER::UI;
+
+const char *POPUP_EXEC = "/usr/bin/cert-checker-popup"; // check-checker-popup binary
+
+std::string response_to_str (response_e response)
+{
+ switch (response) {
+ case response_e::DONT_UNINSTALL:
+ return "DONT_UNINSTALL";
+ case response_e::UNINSTALL:
+ return "UNINSTALL";
+ default:
+ return "RESPONSE_ERROR";
+ }
+}
+
+int wait_for_popup (int popup_pid, int timeout)
+{
+ int status;
+ int ret;
+
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &set, NULL);
+ siginfo_t info;
+ struct timespec time = {timeout, 0L};
+
+ if (timeout > 0)
+ ret = TEMP_FAILURE_RETRY(sigtimedwait(&set, &info, &time));
+ else
+ ret = TEMP_FAILURE_RETRY(sigwaitinfo(&set, &info));
+
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
+
+ if (ret == -1 && errno == EAGAIN) {
+ LogError("POPUP TIMEOUT");
+ goto err;
+ }
+ else if (ret == SIGCHLD && info.si_pid == popup_pid) {
+ // call waitpid on the child process to get rid of zombie process
+ waitpid(popup_pid, NULL, 0);
+
+ // The proper signal has been caught and its pid matches to popup_pid
+ // Now check the popup exit status
+ status = WEXITSTATUS(info.si_status);
+ LogDebug("STATUS EXIT ON POPUP (CHILD: " << info.si_pid << "): " << status);
+
+ switch (static_cast<popup_status>(status)) {
+
+ case popup_status::NO_ERROR:
+ LogDebug("NO_ERROR");
+ return 0;
+
+ case popup_status::EXIT_ERROR:
+ LogError("ERROR");
+ return -1;
+
+ default: // Unknown exit status
+ LogError("UNKNOWN_ERROR");
+ return -1;
+ }
+ }
+ else {
+ LogError("Some other signal has been caught (pid: " << info.si_pid << ", signal: " << info.si_signo << ")");
+ goto err;
+ }
+
+err:
+ // kill popup process and return error
+ kill(popup_pid, SIGKILL);
+
+ // call waitpid on the child process to get rid of zombie process
+ waitpid(popup_pid, NULL, 0);
+ return -1;
+}
+
+void child_process (int fd_send_to_child[2], int fd_send_to_parent[2])
+{
+ LogDebug("Child");
+
+ // read data from parent
+ close(fd_send_to_child[1]);
+
+ // send data to parent
+ close(fd_send_to_parent[0]);
+
+ std::stringstream pipe_in_buff;
+ std::stringstream pipe_out_buff;
+ pipe_in_buff << fd_send_to_parent[1];
+ pipe_out_buff << fd_send_to_child[0];
+ std::string pipe_in = pipe_in_buff.str();
+ std::string pipe_out = pipe_out_buff.str();
+
+ LogDebug("Passed file descriptors: " << fd_send_to_child[0] << ", "<< fd_send_to_parent[1]);
+
+ if (execl(POPUP_EXEC, POPUP_EXEC, pipe_out.c_str(), pipe_in.c_str(), NULL) < 0){
+ LogError("execl FAILED");
+ }
+
+ LogError("This should not happen!!!");
+ _exit(response_e::RESPONSE_ERROR);
+}
+
+int send_message_to_child(const BinaryStream &stream, int fd_send_to_child)
+{
+ LogDebug("Sending message to popup-bin process");
+ unsigned int begin = 0;
+ int tmp;
+ while (begin < stream.size()) {
+ tmp = TEMP_FAILURE_RETRY(write(fd_send_to_child,
+ stream.char_pointer() + begin,
+ stream.size() - begin));
+ if(-1 == tmp){
+ LogError("Write to pipe failed!");
+ return -1;
+ }
+ begin += tmp;
+ }
+ LogDebug("Message has been sent");
+ return 0;
+}
+
+response_e parse_response (int count, char *data)
+{
+ LogDebug("RESULT FROM POPUP PIPE (CHILD) : [ " << count << " ]");
+ int response_int;
+ response_e response;
+ BinaryStream stream_in;
+ stream_in.Write(count, data);
+ CCHECKER::Deserialization::Deserialize(stream_in, response_int);
+ response = static_cast <response_e> (response_int);
+ LogDebug("response :" << response_to_str(response));
+ return response;
+}
+
+} // anonymous namespace
+
+namespace CCHECKER {
+namespace UI {
+
+// BinaryStream class implementation
+void BinaryStream::Read(size_t num, void * bytes)
+{
+ size_t max_size = m_data.size();
+ for (size_t i = 0; i < num; ++i) {
+ if( i + m_readPosition >= max_size){
+ return;
+ }
+ static_cast <unsigned char*> (bytes)[i] = m_data[i + m_readPosition];
+ }
+ m_readPosition += num;
+}
+
+void BinaryStream::Write(size_t num, const void * bytes)
+{
+ for (size_t i = 0; i < num; ++i) {
+ m_data.push_back(static_cast <const unsigned char*> (bytes)[i]);
+ }
+}
+
+BinaryStream::BinaryStream() :
+ m_readPosition(0)
+{}
+
+BinaryStream::~BinaryStream() {}
+
+const unsigned char* BinaryStream::char_pointer() const
+{
+ return &m_data[0];
+}
+
+size_t BinaryStream::size() const
+{
+ return m_data.size();
+}
+// BinaryStream
+
+response_e run_popup(
+ const app_t &app,
+ int timeout)
+{
+ LogDebug(app.str());
+
+ // serialization
+ BinaryStream stream;
+ CCHECKER::Serialization::Serialize(stream, app.app_id);
+ CCHECKER::Serialization::Serialize(stream, app.pkg_id);
+
+ int fd_send_to_child[2];
+ int fd_send_to_parent[2];
+ pid_t childpid;
+
+ if(0 != pipe(fd_send_to_child)){
+ LogError("Cannot create pipes!");
+ return response_e::RESPONSE_ERROR;
+ }
+ if(0 != pipe(fd_send_to_parent)){
+ LogError("Cannot create pipes!");
+ close(fd_send_to_child[0]);
+ close(fd_send_to_child[1]);
+ return response_e::RESPONSE_ERROR;
+ }
+
+ if ((childpid = fork()) == -1) {
+ LogError("Fork() ERROR");
+ close(fd_send_to_child[0]);
+ close(fd_send_to_parent[1]);
+ goto error;
+ }
+
+ if(childpid == 0) { // Child process
+ child_process (fd_send_to_child, fd_send_to_parent);
+ }
+ else { // Parent process
+ LogDebug("Parent (child pid: " << childpid << ")");
+
+ // send data to child
+ close(fd_send_to_child[0]);
+
+ // read data from child
+ close(fd_send_to_parent[1]);
+
+ // writing to child
+ if (send_message_to_child(stream, fd_send_to_child[1]))
+ goto error;
+
+ // wait for child
+ if (wait_for_popup(childpid, timeout) != 0 )
+ goto error;
+
+ // Read message from popup (child)
+ int buff_size = 1024;
+ char result[buff_size];
+ int count;
+ count = TEMP_FAILURE_RETRY(read(fd_send_to_parent[0], result, buff_size));
+
+ // Parsing response from child
+ response_e response;
+ if (0 < count)
+ response = parse_response(count, result);
+ else {
+ LogDebug("ERROR, count = " << count);;
+ goto error;
+ }
+
+ LogDebug("popup-runner: EXIT SUCCESS");
+ // cleanup
+ close(fd_send_to_parent[0]);
+ close(fd_send_to_child[1]);
+ return response;
+ }
+
+ LogError("This should not happen!!!");
+error:
+ // cleanup
+ LogDebug("popup-runner: EXIT ERROR");
+ close(fd_send_to_parent[0]);
+ close(fd_send_to_child[1]);
+ return response_e::RESPONSE_ERROR;
+}
+
+} // UI
+} // CCHECKER