lxcpp: fix cgroup unit tests
[platform/core/security/vasum.git] / server / zone-provision.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Mateusz Malicki <m.malicki2@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file
21  * @author  Mateusz Malicki (m.malicki2@samsung.com)
22  * @brief   Implementation of class for managing zone provsion
23  */
24
25 #include "config.hpp"
26
27 #include "zone-provision.hpp"
28 #include "zone-provision-config.hpp"
29
30 #include "logger/logger.hpp"
31 #include "utils/fs.hpp"
32 #include "utils/exception.hpp"
33 #include "config/manager.hpp"
34 #include "vasum-client.h"
35
36 #include <boost/filesystem.hpp>
37
38 #include <string>
39 #include <algorithm>
40 #include <fcntl.h>
41
42 namespace fs = boost::filesystem;
43
44 using namespace utils;
45
46 namespace vasum {
47
48 ZoneProvision::ZoneProvision(const std::string& rootPath,
49                              const std::string& configPath,
50                              const std::string& dbPath,
51                              const std::string& dbPrefix,
52                              const std::vector<std::string>& validLinkPrefixes)
53     : mRootPath(rootPath)
54     , mDbPath(dbPath)
55     , mDbPrefix(dbPrefix)
56     , mValidLinkPrefixes(validLinkPrefixes)
57 {
58     config::loadFromKVStoreWithJsonFile(dbPath, configPath, mProvisioningConfig, dbPrefix);
59 }
60
61 ZoneProvision::~ZoneProvision()
62 {
63     stop();
64 }
65
66 void ZoneProvision::saveProvisioningConfig()
67 {
68     config::saveToKVStore(mDbPath, mProvisioningConfig, mDbPrefix);
69 }
70
71 std::string ZoneProvision::declareProvision(ZoneProvisioningConfig::Provision&& provision)
72 {
73     std::string id = getId(provision);
74     auto it = std::find_if(mProvisioningConfig.provisions.begin(),
75                            mProvisioningConfig.provisions.end(),
76                            [&](const ZoneProvisioningConfig::Provision& existingProvision) {
77                                return getId(existingProvision) == id;
78                            });
79     if (it != mProvisioningConfig.provisions.end()) {
80         const std::string msg = "Can't add provision. It already exists: " + id;
81         LOGE(msg);
82         throw ProvisionExistsException(msg);
83     }
84     mProvisioningConfig.provisions.push_back(std::move(provision));
85     saveProvisioningConfig();
86     return id;
87 }
88
89 std::string ZoneProvision::declareFile(const int32_t& type,
90                                        const std::string& path,
91                                        const int32_t& flags,
92                                        const int32_t& mode)
93 {
94     ZoneProvisioningConfig::Provision provision;
95     provision.set(ZoneProvisioningConfig::File({type, path, flags, mode}));
96
97     return declareProvision(std::move(provision));
98 }
99
100 std::string ZoneProvision::declareMount(const std::string& source,
101                                         const std::string& target,
102                                         const std::string& type,
103                                         const int64_t& flags,
104                                         const std::string& data)
105 {
106     ZoneProvisioningConfig::Provision provision;
107     provision.set(ZoneProvisioningConfig::Mount({source, target, type, flags, data}));
108
109     return declareProvision(std::move(provision));
110 }
111
112 std::string ZoneProvision::declareLink(const std::string& source,
113                                        const std::string& target)
114 {
115     ZoneProvisioningConfig::Provision provision;
116     provision.set(ZoneProvisioningConfig::Link({source, target}));
117
118     return declareProvision(std::move(provision));
119 }
120
121 void ZoneProvision::start() noexcept
122 {
123     for (const auto& provision : mProvisioningConfig.provisions) {
124         try {
125             if (provision.is<ZoneProvisioningConfig::File>()) {
126                 file(provision.as<ZoneProvisioningConfig::File>());
127             } else if (provision.is<ZoneProvisioningConfig::Mount>()) {
128                 mount(provision.as<ZoneProvisioningConfig::Mount>());
129             } else if (provision.is<ZoneProvisioningConfig::Link>()) {
130                 link(provision.as<ZoneProvisioningConfig::Link>());
131             }
132             // mProvisioned must be FILO
133             mProvisioned.push_front(provision);
134         } catch (const std::exception& ex) {
135             LOGE("Provsion error: " << ex.what());
136         }
137     }
138 }
139
140 void ZoneProvision::stop() noexcept
141 {
142     mProvisioned.remove_if([this](const ZoneProvisioningConfig::Provision& provision) -> bool {
143         try {
144             if (provision.is<ZoneProvisioningConfig::Mount>()) {
145                 umount(provision.as<ZoneProvisioningConfig::Mount>());
146             }
147             // leaves files, links, fifo, untouched
148             return true;
149         } catch (const std::exception& ex) {
150             LOGE("Provsion error: " << ex.what());
151             return false;
152         }
153     });
154 }
155
156 std::vector<std::string> ZoneProvision::list() const
157 {
158     std::vector<std::string> items;
159     for (const auto& provision : mProvisioningConfig.provisions) {
160         items.push_back(getId(provision));
161     }
162     return items;
163 }
164
165 void ZoneProvision::remove(const std::string& item)
166 {
167
168     const auto it = std::find_if(mProvisioningConfig.provisions.begin(),
169                                  mProvisioningConfig.provisions.end(),
170                                  [&](const ZoneProvisioningConfig::Provision& provision) {
171                                     return getId(provision) == item;
172                                  });
173     if (it == mProvisioningConfig.provisions.end()) {
174         throw UtilsException("Can't find provision");
175     }
176
177     mProvisioningConfig.provisions.erase(it);
178     LOGI("Provision removed: " << item);
179 }
180
181 void ZoneProvision::file(const ZoneProvisioningConfig::File& config)
182 {
183     bool ret = false;
184     const fs::path hostPath = fs::path(mRootPath) / fs::path(config.path);
185     switch (config.type) {
186         case VSMFILE_DIRECTORY:
187             ret = utils::createDirs(hostPath.string(), config.mode);
188             if (!ret) {
189                 throw UtilsException("Can't create dir: " + hostPath.string());
190             }
191             break;
192
193         case VSMFILE_FIFO:
194             ret = utils::createFifo(hostPath.string(), config.mode);
195             if (!ret) {
196                 throw UtilsException("Failed to make fifo: " + config.path);
197             }
198             break;
199
200         case VSMFILE_REGULAR:
201             if ((config.flags & O_CREAT)) {
202                 ret = utils::createFile(hostPath.string(), config.flags, config.mode);
203                 if (!ret) {
204                     throw UtilsException("Failed to create file: " + config.path);
205                 }
206             } else {
207                 ret = utils::copyFile(config.path, hostPath.string());
208                 if (!ret) {
209                     throw UtilsException("Failed to copy file: " + config.path);
210                 }
211             }
212             break;
213     }
214 }
215
216 void ZoneProvision::mount(const ZoneProvisioningConfig::Mount& config)
217 {
218     const fs::path hostPath = fs::path(mRootPath) / fs::path(config.target);
219     bool ret = utils::mount(config.source,
220                             hostPath.string(),
221                             config.type,
222                             config.flags,
223                             config.data);
224     if (!ret) {
225         throw UtilsException("Mount operation failure - source : " + config.source);
226     }
227 }
228
229 void ZoneProvision::umount(const ZoneProvisioningConfig::Mount& config)
230 {
231     const fs::path hostPath = fs::path(mRootPath) / fs::path(config.target);
232     bool ret = utils::umount(hostPath.string());
233     if (!ret) {
234         throw UtilsException("Umount operation failure - path : " + config.target);
235     }
236 }
237
238 void ZoneProvision::link(const ZoneProvisioningConfig::Link& config)
239 {
240     const std::string srcHostPath = fs::path(config.source).normalize().string();
241     for (const std::string& prefix : mValidLinkPrefixes) {
242         if (prefix.length() <= srcHostPath.length()
243             && srcHostPath.compare(0, prefix.length(), prefix) == 0) {
244
245             const fs::path destHostPath = fs::path(mRootPath) / fs::path(config.target);
246             bool ret = utils::createLink(srcHostPath, destHostPath.string());
247             if (!ret) {
248                 throw UtilsException("Failed to create hard link: " +  config.source);
249             }
250             return;
251         }
252     }
253     const std::string msg = "Failed to create hard link: path=host: " +
254                             srcHostPath + ", msg: Path prefix is not valid path";
255     LOGE(msg);
256     throw UtilsException(msg);
257 }
258
259 std::string ZoneProvision::getId(const ZoneProvisioningConfig::File& file)
260 {
261     //TODO output of type,flags and mode should be more user friendly
262     return "file " +
263            file.path + " " +
264            std::to_string(file.type) + " " +
265            std::to_string(file.flags) + " " +
266            std::to_string(file.mode);
267 }
268
269 std::string ZoneProvision::getId(const ZoneProvisioningConfig::Mount& mount)
270 {
271     //TODO output of flags should be more user friendly
272     return "mount " +
273            mount.source + " " +
274            mount.target + " " +
275            mount.type + " " +
276            std::to_string(mount.flags) + " " +
277            mount.data;
278 }
279
280 std::string ZoneProvision::getId(const ZoneProvisioningConfig::Link& link)
281 {
282     return "link " + link.source + " " + link.target;
283 }
284
285 std::string ZoneProvision::getId(const ZoneProvisioningConfig::Provision& provision)
286 {
287     using namespace vasum;
288     if (provision.is<ZoneProvisioningConfig::File>()) {
289         return getId(provision.as<ZoneProvisioningConfig::File>());
290     } else if (provision.is<ZoneProvisioningConfig::Mount>()) {
291         return getId(provision.as<ZoneProvisioningConfig::Mount>());
292     } else if (provision.is<ZoneProvisioningConfig::Link>()) {
293         return getId(provision.as<ZoneProvisioningConfig::Link>());
294     }
295     throw UtilsException("Unknown provision type");
296 }
297
298 } // namespace vasum