9cc7cd7bab330db7843355bc2bc79f1a57c3bc86
[framework/web/wrt-commons.git] / modules / ace / engine / ConfigurationManager.cpp
1 /*
2  * Copyright (c) 2011 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 #include <dpl/assert.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #include <error.h>
20 #include <malloc.h>
21 #include <sys/stat.h>
22 #include <dpl/ace/ConfigurationManager.h>
23
24 using namespace std;
25
26 namespace {
27 const string currentXMLSchema("bondixml.xsd");
28 }
29
30 ConfigurationManager * ConfigurationManager::instance = NULL;
31
32 string ConfigurationManager::getCurrentPolicyFile(void) const
33 {
34     return currentPolicyFile;
35 }
36
37 string ConfigurationManager::getFullPathToCurrentPolicyFile(void) const
38 {
39     if (*(storagePath.rbegin()) == '/') {
40         return storagePath + currentPolicyFile;
41     }
42     return storagePath + "/" + currentPolicyFile;
43 }
44
45 string ConfigurationManager::getStoragePath(void) const
46 {
47     return storagePath;
48 }
49
50 string ConfigurationManager::getFullPathToCurrentPolicyXMLSchema() const
51 {
52     if (*(storagePath.rbegin()) == '/')
53     {
54         return storagePath + currentXMLSchema;
55     }
56     return storagePath + "/" + currentXMLSchema;
57 }
58
59 int ConfigurationManager::parse(const string &configFileName)
60 {
61     configFile = configFileName;
62     int error = PARSER_SUCCESS;
63     policyFiles.clear();
64
65     reader = xmlNewTextReaderFilename(configFile.c_str());
66
67     if (reader == NULL) {
68         LogError("Parser does not exist");
69         error = PARSER_ERROR;
70         goto cleanUp;
71     }
72
73     if (xmlTextReaderSetParserProp(reader, XML_PARSER_VALIDATE, 1)) {
74         LogError("Error while setting parser validating.");
75         error = PARSER_ERROR;
76         Assert(false && "Cannot make XML parser validating");
77         goto cleanUp;
78     }
79
80     if (xmlTextReaderSetParserProp(reader, XML_PARSER_DEFAULTATTRS, 1)) {
81         LogError("Error while attribute defaulting.");
82         error = PARSER_ERROR;
83         Assert(false && "XML Parser cannot default xml attributes");
84         goto cleanUp;
85     }
86
87     int ret;
88     while (1 == (ret = xmlTextReaderRead(reader))) {
89         processNode();
90         if (xmlTextReaderIsValid(reader) == 0) {
91             LogError(
92                 "Parser error while reading file " << configFile <<
93                 ". File is not valid.");
94             error = PARSER_ERROR;
95             Assert(false && "Configuration Manager error");
96             goto cleanUp;
97         }
98     }
99     if (ret != 0) {
100         LogError("There were some errors while parsing XML file.");
101     }
102
103 cleanUp:
104     if (reader != NULL) {
105         xmlFreeTextReader(reader);
106     }
107     return error;
108 }
109
110 void ConfigurationManager::extractFileAttributes()
111 {
112     xmlChar *active = xmlTextReaderGetAttribute(reader, ATTR_ACTIVE_POLICY);
113     xmlActive = false;
114
115     if (active && active[0] == 't') {
116         xmlActive = true;
117     }
118
119     xmlFree(active);
120 }
121
122 void ConfigurationManager::startNodeHandler(void)
123 {
124     xmlChar *name = xmlTextReaderName(reader);
125     switch (*name) {
126     case 'f':     // file
127         extractFileAttributes();
128         break;
129     default:
130         break;
131     }
132     xmlFree(name);
133 }
134
135 void ConfigurationManager::endNodeHandler(void)
136 {
137     xmlChar *name = xmlTextReaderName(reader);
138     switch (*name) {
139     case 'f':
140         policyFiles.push_back(currentText);
141         if (xmlActive) {
142             currentPolicyFile = currentText;
143             xmlActive = false;
144         }
145         currentText.clear();
146         break;
147     case 's':
148         storagePath = currentText;
149         currentText.clear();
150         break;
151     default:
152         break;
153     }
154     xmlFree(name);
155 }
156
157 void ConfigurationManager::textNodeHandler(void)
158 {
159     xmlChar *text = xmlTextReaderValue(reader);
160     currentText = reinterpret_cast<const char*>(text);
161     xmlFree(text);
162 }
163
164 void ConfigurationManager::processNode(void)
165 {
166     xmlReaderTypes type =
167         static_cast<xmlReaderTypes>(xmlTextReaderNodeType(reader));
168     switch (type) {
169     case XML_READER_TYPE_ELEMENT: startNodeHandler();
170         break;
171     case XML_READER_TYPE_END_ELEMENT: endNodeHandler();
172         break;
173     case XML_READER_TYPE_TEXT: textNodeHandler();
174         break;
175     default:
176         break;
177     }
178 }
179
180 int ConfigurationManager::addPolicyFile(const string & sourcePath)
181 {
182     FILE * sourceFd = NULL, *destFd = NULL;
183     int flag = CM_OPERATION_SUCCESS;
184     int sourceLength;
185     string fileName;
186
187     string newFilePath(getStoragePath());
188     newFilePath.append("/");
189
190     if (sourcePath.empty()) {
191         LogError("Filename empty");
192         flag = CM_GENERAL_ERROR;
193         goto cleanup;
194     }
195
196     fileName = extractFilename(sourcePath);
197     newFilePath.append(fileName);
198
199     LogDebug("Adding new file " << newFilePath);
200     if (checkIfFileExistst(newFilePath)) {
201         LogError("Destination file already exists");
202         flag = CM_FILE_EXISTS;
203         goto cleanup;
204     }
205
206     sourceFd = fopen(sourcePath.c_str(), "r");
207     if (sourceFd == NULL) {
208         LogError("Source file opening failed");
209         flag = CM_GENERAL_ERROR;
210         goto cleanup;
211     }
212
213     destFd = fopen(newFilePath.c_str(), "w");
214     if (destFd == NULL) {
215         LogError("Destination file creation failed");
216         flag = CM_GENERAL_ERROR;
217         goto cleanup;
218     }
219
220     if (0 > (sourceLength = getFileSize(sourcePath))) {
221         LogError("getFileSize error");
222         flag = CM_GENERAL_ERROR;
223         goto cleanup;
224     }
225
226     if (!copyFile(sourceFd, destFd, sourceLength)) {
227         //Copying failed, we have to remove corrupted file
228         flag = CM_GENERAL_ERROR;
229         if (removePolicyFile(newFilePath) != CM_OPERATION_SUCCESS) {
230             flag = CM_REMOVE_ERROR;
231         }
232         goto cleanup;
233     }
234     policyFiles.push_back(fileName);
235
236     if (saveConfig() != CM_OPERATION_SUCCESS) {
237         LogError("Error while saving policy file");
238         //TODO HOW TO ROLLBACK save config?
239     }
240
241 cleanup:
242
243     if (sourceFd) {
244         fclose(sourceFd);
245     }
246     if (destFd) {
247         fclose(destFd);
248     }
249
250     return flag;
251 }
252
253 int ConfigurationManager::removePolicyFile(const string& file)
254 {
255     LogDebug("Trying to remove policy " << file);
256     int errorFlag = CM_OPERATION_SUCCESS;
257     string fileName = extractFilename(file);
258     string filePath(CONFIGURATION_MGR_TEST_POLICY_STORAGE);
259
260     if (fileName == currentPolicyFile) {
261         errorFlag = CM_REMOVE_CURRENT;
262         LogError("Cannot remove current policy");
263         goto end;
264     }
265
266     filePath.append("/").append(fileName);
267
268     if (remove(filePath.c_str()) != 0) {
269         if (checkIfFileExistst(filePath)) {
270             errorFlag = CM_REMOVE_ERROR;
271             LogError("Cannot delete file" << filePath);
272             goto end;
273         }
274         LogError("Cannot delete file" << filePath << " the file doesn't exist");
275         errorFlag = CM_REMOVE_NOT_EXISTING;
276     } else {
277         errorFlag = CM_OPERATION_SUCCESS;
278     }
279     //If remove was successful or unsuccessful but file doesn't exists then it
280     //should be removed from the list of available policies
281     policyFiles.remove(fileName);
282
283 end:
284     return errorFlag;
285 }
286
287 string ConfigurationManager::extractFilename(const string & sourcePath) const
288 {
289     //begining of filename without path
290     size_t filenamePos = sourcePath.rfind('/');
291
292     string tmp;
293     if (filenamePos == string::npos) {
294         tmp = sourcePath;
295     } else {
296         tmp = sourcePath.substr(filenamePos + 1);
297     }
298     LogDebug("Extracted filename " << tmp);
299     return tmp;
300 }
301
302 int ConfigurationManager::getFileSize(const string & path) const
303 {
304     //get source file size
305     struct stat sourceStat;
306     int sourceLength;
307     if (stat(path.c_str(), &sourceStat) == -1) {
308         LogError("Reading file properties failed");
309         sourceLength = -1;
310     } else {
311         sourceLength = sourceStat.st_size;
312     }
313     return sourceLength;
314 }
315
316 bool ConfigurationManager::copyFile(FILE * sourceDesc,
317         FILE * destinationDesc,
318         int lenght) const
319 {
320     int rv;
321     char *buffer = static_cast<char *>(malloc(lenght));
322     bool result = true;
323
324     if (!buffer) {
325         return false;
326     }
327
328     while ((rv = fread(buffer, sizeof (char), lenght, sourceDesc)) > 0) {
329         if (rv != lenght) {
330             if (!feof(sourceDesc)) {
331                 LogError("Error while reading file ");
332                 result = false;
333                 break;
334             }
335         }
336
337         rv = fwrite(buffer, sizeof (char), lenght, destinationDesc);
338         if (rv != lenght) {
339             LogError("Write file failed ");
340             result = false;
341             break;
342         }
343     }
344     free(buffer);
345     return result;
346 }
347
348 bool ConfigurationManager::checkIfFileExistst(const string & newFilePath) const
349 {
350     bool exists = false;
351     struct stat stats;
352     if (stat(newFilePath.c_str(), &stats) == 0) {
353         exists = true;
354     }
355     return exists;
356 }
357
358 int ConfigurationManager::changeCurrentPolicyFile(const std::string & fileName)
359 {
360     int result = CM_OPERATION_SUCCESS;
361     string oldPolicyFile = currentPolicyFile;
362
363     string filePath(getStoragePath() + "/");
364     filePath += fileName;
365
366     if (!checkIfFileExistst(filePath)) {
367         //Policy file doesn't exist
368         result = CM_GENERAL_ERROR;
369         LogError("Error: policy file " << filePath << " doesn't exist");
370         goto end;
371     }
372     if (result == CM_OPERATION_SUCCESS) {
373         //Adding file to storage succeeded
374         currentPolicyFile = extractFilename(filePath);
375         //Try to save the configuration file
376         result = saveConfig();
377     }
378     if (result != CM_OPERATION_SUCCESS) {
379         //rollback changes
380         currentPolicyFile = oldPolicyFile;
381         LogError("Error while saving policy file");
382         //TODO HOW TO ROLLBACK save config?
383     }
384
385 end:
386     return result;
387 }
388
389 int ConfigurationManager::saveConfig()
390 {
391     std::ofstream output(configFile.c_str());
392     int errorFlag = CM_OPERATION_SUCCESS;
393
394     output << "<?xml version=\"1.0\" ?>" << std::endl;
395     output <<
396     "<!DOCTYPE manager-settings SYSTEM \"" ACE_CONFIGURATION_DTD "\">" <<
397     std::endl;
398     output << "<manager-settings>" << std::endl;
399     output << "  <storage-path>" << storagePath << "</storage-path>" <<
400     std::endl;
401     output << "  <policy-files>" << std::endl;
402     for (list<string>::const_iterator it = policyFiles.begin();
403          it != policyFiles.end();
404          ++it) {
405         output << "\t<file ";
406         if (*it == currentPolicyFile) {
407             output << "active=\"true\"";
408         }
409         output << ">" << *it << "</file>" << std::endl;
410     }
411     output << "  </policy-files>\n";
412     output << " </manager-settings>";
413     output.close();
414
415     //TODO should we add 'eof' here?
416     if (output.bad() || output.fail()) {
417         //There were some errors while writing to file
418         errorFlag = CM_GENERAL_ERROR;
419     }
420
421     return errorFlag;
422 }