Change data type for two attributes of <tizen:box-content> on xsd schema
[framework/web/wrt-installer.git] / src / jobs / widget_install / task_plugins_copy.cpp
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file    task_plugin_copy.cpp
18  * @author  Marcin Kaminski (marcin.ka@samsung.com)
19  * @version 1.0
20  * @brief   Copying plugins delivered in widget package.
21  */
22
23 #include <unistd.h>
24 #include "task_plugins_copy.h"
25 #include <dpl/log/log.h>
26 #include <dpl/string.h>
27 #include <dpl/utils/wrt_utility.h>
28 #include <dpl/errno_string.h>
29 #include <widget_install/job_widget_install.h>
30 #include <widget_install_context.h>
31 #include <widget_install/widget_install_errors.h>
32 #include <dpl/exception.h>
33 /* Headers needed for listing directories */
34 #include <sys/stat.h>
35 #include <dirent.h>
36 /* Installation expceptions support */
37 #include <dpl/exception.h>
38 #include <cerrno>
39
40 /* wrt-installer has to copy plugins for ARM architecture
41  * when running on target or for i586 architecture if launched
42  * on SDK emulator. */
43 #ifdef __arm__
44 const std::string plugins_dir = "arm";
45 #else
46 const std::string plugins_dir = "i586";
47 #endif
48
49 namespace {
50 const std::string PackagePluginsDir = "/plugins/";
51 const std::string InstallationPluginsDir = "/data/.netscape/plugins/";
52 const mode_t InstallationPluginsDirMode = 0755;
53 }
54
55 namespace Jobs {
56 namespace WidgetInstall {
57 TaskPluginsCopy::TaskPluginsCopy(InstallerContext& context) :
58     DPL::TaskDecl<TaskPluginsCopy>(this),
59     m_context(context)
60 {
61     LogDebug("Starting widget plugins copy task");
62     AddStep(&TaskPluginsCopy::StepFindPlugins);
63     AddStep(&TaskPluginsCopy::StepCopyPlugins);
64     AddStep(&TaskPluginsCopy::StepCopyingFinished);
65     LogDebug("Widget plugins copy task ended");
66     m_npsource = m_context.locations->getSourceDir() + PackagePluginsDir
67         + plugins_dir;
68     m_npdestination = m_context.locations->getPackageInstallationDir()
69         + InstallationPluginsDir;
70 }
71
72 void TaskPluginsCopy::StepFindPlugins()
73 {
74     LogDebug("Starting plugins finding step");
75     /* Check whether plugins directory for actual architecture exists
76      * (plugins for other architectures are omitted even they exists). */
77     if (!WrtUtilDirExists(m_npsource)) {
78         LogDebug(
79             "Plugins directory (" << m_npsource
80                                   <<
81             ") does not exists - skipping copy step");
82         SwitchToStep(&TaskPluginsCopy::StepCopyingFinished);
83         return;
84     }
85
86     /* Find all .so files and store their names in list */
87     DIR *dir;
88     struct stat st;
89     LogDebug("Opening plugins directory");
90     dir = opendir(m_npsource.c_str());
91     if (dir == NULL) {
92         LogError("Unable to open plugins directory");
93         ThrowMsg(Exceptions::FileOperationFailed, "Unable to read plugins directory");
94     }
95     std::string tempname;
96     struct dirent entry;
97     struct dirent *result;
98     int return_code;
99     errno = 0;
100     const std::string ext(".so");
101     /* Listing directory and checking entries found inside */
102     for (return_code = readdir_r(dir, &entry, &result);
103                 result != NULL && return_code == 0;
104                 return_code = readdir_r(dir, &entry, &result))
105     {
106         tempname = m_npsource + "/" + entry.d_name;
107         if (lstat(tempname.c_str(), &st) != 0) {
108             LogWarning(
109                 "Failed to call \"lstat\" (errno:" << errno
110                                                    <<
111                 ") on entry - skipping");
112             continue;
113         }
114         /* Directories other than "." and ".." should not be found*/
115         if (S_ISDIR(st.st_mode)) {
116             if (strncmp(entry.d_name, "..", 2) != 0
117                 && strncmp(entry.d_name, ".", 1) != 0)
118             {
119                 LogError("Directory detected instead of plugin file: "
120                          << entry.d_name);
121                 /* Subdirectories inside plugins/ARCH are not supported */
122                 if (-1 == TEMP_FAILURE_RETRY(closedir(dir))) {
123                     LogError(
124                         "Failed to close dir: " << m_npsource
125                                                 << " with error: " <<
126                         DPL::GetErrnoString());
127                 }
128                 ThrowMsg(
129                     Exceptions::PluginsSubdirectory,
130                     "Subdirectories inside plugins directory are not supported");
131             } else {
132                 continue;
133             }
134         }
135
136         tempname = std::string(entry.d_name);
137         /* Check whether file extension is ".so" */
138         if (tempname.compare(tempname.size() - ext.size(), ext.size(),
139                              ext) == 0)
140         {
141             /* Plugin file found */
142             LogDebug("Plugin file found: " << tempname);
143             m_nplugins.push_back(tempname);
144         } else {
145             /* Non-.so file found in plugins directory- skipping */
146             LogWarning("Non-plugin file found: " << tempname);
147         }
148     }
149     if (return_code != 0 || errno != 0) {
150         LogError("readdir_r() failed with " << DPL::GetErrnoString());
151     }
152     errno = 0;
153     if (-1 == TEMP_FAILURE_RETRY(closedir(dir))) {
154         LogError("Failed to close dir: " << m_npsource << " with error: "
155                                          << DPL::GetErrnoString());
156     }
157     /* If no .so files found (list is empty) abort taks*/
158     if (m_nplugins.empty()) {
159         LogError("No valid plugin files found");
160         ThrowMsg(Exceptions::EmptyPluginsDirectory, "No valid plugin found");
161     }
162     LogDebug("Number of detected plugins: " << m_nplugins.size());
163     LogDebug("Plugins finding step ended");
164 }
165
166 void TaskPluginsCopy::StepCopyPlugins()
167 {
168     LogDebug("Starting plugins copying step");
169     std::string source;
170     std::string destination;
171
172     /* Create new directory for plugins (data/.netscape/plugins/) */
173     LogDebug("Creating destination plugin directory");
174     if (!WrtUtilMakeDir(m_npdestination, InstallationPluginsDirMode)) {
175         LogError("Failed to create directory for plugins");
176         ThrowMsg(Exceptions::FileOperationFailed,
177                  "Failed to create directory for plugins");
178     }
179
180     LogDebug("Copying plugins to: " << m_npdestination);
181     /* Copy plugins from widget package into
182      * .netscape/plugins in widget's target directory */
183     for (std::list<std::string>::const_iterator it = m_nplugins.begin();
184          it != m_nplugins.end(); ++it)
185     {
186         LogDebug("Copying plugin file: " << (*it));
187         source = m_npsource + "/" + (*it);
188         destination = m_npdestination + (*it);
189         if (rename(source.c_str(), destination.c_str()) != 0) {
190             LogError("Failed to move " << source << " to " << destination);
191             LogError("(errno: " << errno << ")");
192             ThrowMsg(Exceptions::FileOperationFailed, "Failed to copy plugin file");
193         }
194     }
195
196     /* Remove last part of path in source directory path
197      * (that is "arm" or "i586" depending on architecture) */
198     size_t position = m_npsource.find_last_of('/');
199     source = m_npsource.substr(0, position);
200     LogDebug("Removing unnecessary directory: " << source);
201     /* Remove source directory with plugins (possibly for multiple
202      * architectures). */
203     if (!WrtUtilRemove(source)) {
204         LogError("Failed to plugins source remove directory");
205         ThrowMsg(Exceptions::FileOperationFailed,
206                  "Failed to plugins source remove directory");
207     }
208     LogDebug("Plugins copying step ended");
209
210     m_context.job->UpdateProgress(
211             InstallerContext::INSTALL_PLUGINS_COPY,
212             "Plugins copy");
213 }
214
215 void TaskPluginsCopy::StepCopyingFinished()
216 {
217     LogDebug("Plugins copy task finished");
218 }
219 } //namespace WidgetInstall
220 } //namespace Jobs