2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Jan Olszak <j.olszak@samsung.com>
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * @author Jan Olszak (j.olszak@samsung.com)
22 * @brief Definition of the class for managing zones
27 #include "host-dbus-definitions.hpp"
28 #include "common-dbus-definitions.hpp"
29 #include "zone-dbus-definitions.hpp"
30 #include "zones-manager.hpp"
31 #include "zone-admin.hpp"
32 #include "lxc/cgroup.hpp"
33 #include "exception.hpp"
35 #include "utils/paths.hpp"
36 #include "logger/logger.hpp"
37 #include "config/manager.hpp"
38 #include "dbus/exception.hpp"
39 #include "utils/fs.hpp"
40 #include "utils/img.hpp"
41 #include "utils/environment.hpp"
43 #include <boost/filesystem.hpp>
44 #include <boost/regex.hpp>
45 #include <boost/exception/diagnostic_information.hpp>
56 bool regexMatchVector(const std::string& str, const std::vector<boost::regex>& v)
58 for (const boost::regex& toMatch: v) {
59 if (boost::regex_match(str, toMatch)) {
67 const std::string DB_PREFIX = "daemon";
68 const std::string HOST_ID = "host";
69 const std::string ENABLED_FILE_NAME = "enabled";
71 const boost::regex ZONE_NAME_REGEX("~NAME~");
72 const boost::regex ZONE_IP_THIRD_OCTET_REGEX("~IP~");
73 const boost::regex ZONE_VT_REGEX("~VT~");
75 const unsigned int ZONE_IP_BASE_THIRD_OCTET = 100;
76 const unsigned int ZONE_VT_BASE = 1;
78 std::string getConfigName(const std::string& zoneId)
80 return "zones/" + zoneId + ".conf";
84 void remove(std::vector<T>& v, const T& item)
86 // erase-remove idiom, ask google for explanation
87 v.erase(std::remove(v.begin(), v.end(), item), v.end());
92 ZonesManager::ZonesManager(const std::string& configPath)
93 : mWorker(utils::Worker::create())
94 , mDetachOnExit(false)
96 LOGD("Instantiating ZonesManager object...");
98 config::loadFromJsonFile(configPath, mConfig);
99 config::loadFromKVStoreWithJsonFile(mConfig.dbPath, configPath, mDynamicConfig, DB_PREFIX);
101 mProxyCallPolicy.reset(new ProxyCallPolicy(mConfig.proxyCallRules));
103 using namespace std::placeholders;
104 mHostConnection.setProxyCallCallback(bind(&ZonesManager::handleProxyCall,
105 this, HOST_ID, _1, _2, _3, _4, _5, _6, _7));
107 mHostConnection.setGetZoneDbusesCallback(bind(&ZonesManager::handleGetZoneDbuses,
110 mHostConnection.setGetZoneIdsCallback(bind(&ZonesManager::handleGetZoneIdsCall,
113 mHostConnection.setGetActiveZoneIdCallback(bind(&ZonesManager::handleGetActiveZoneIdCall,
116 mHostConnection.setGetZoneInfoCallback(bind(&ZonesManager::handleGetZoneInfoCall,
119 mHostConnection.setDeclareFileCallback(bind(&ZonesManager::handleDeclareFileCall,
120 this, _1, _2, _3, _4, _5, _6));
122 mHostConnection.setDeclareMountCallback(bind(&ZonesManager::handleDeclareMountCall,
123 this, _1, _2, _3, _4, _5, _6, _7));
125 mHostConnection.setDeclareLinkCallback(bind(&ZonesManager::handleDeclareLinkCall,
126 this, _1, _2, _3, _4));
128 mHostConnection.setSetActiveZoneCallback(bind(&ZonesManager::handleSetActiveZoneCall,
131 mHostConnection.setCreateZoneCallback(bind(&ZonesManager::handleCreateZoneCall,
134 mHostConnection.setDestroyZoneCallback(bind(&ZonesManager::handleDestroyZoneCall,
137 mHostConnection.setShutdownZoneCallback(bind(&ZonesManager::handleShutdownZoneCall,
140 mHostConnection.setStartZoneCallback(bind(&ZonesManager::handleStartZoneCall,
143 mHostConnection.setLockZoneCallback(bind(&ZonesManager::handleLockZoneCall,
146 mHostConnection.setUnlockZoneCallback(bind(&ZonesManager::handleUnlockZoneCall,
149 mHostConnection.setGrantDeviceCallback(bind(&ZonesManager::handleGrantDeviceCall,
150 this, _1, _2, _3, _4));
152 mHostConnection.setRevokeDeviceCallback(bind(&ZonesManager::handleRevokeDeviceCall,
155 for (const auto& zoneConfig : mDynamicConfig.zoneConfigs) {
156 createZone(utils::createFilePath(mConfig.zoneNewConfigPrefix, zoneConfig));
159 // check if default zone exists, throw ZoneOperationException if not found
160 if (!mConfig.defaultId.empty() && mZones.find(mConfig.defaultId) == mZones.end()) {
161 LOGE("Provided default zone ID " << mConfig.defaultId << " is invalid.");
162 throw ZoneOperationException("Provided default zone ID " + mConfig.defaultId +
166 LOGD("ZonesManager object instantiated");
168 if (mConfig.inputConfig.enabled) {
169 LOGI("Registering input monitor [" << mConfig.inputConfig.device.c_str() << "]");
170 mSwitchingSequenceMonitor.reset(
171 new InputMonitor(mConfig.inputConfig,
172 std::bind(&ZonesManager::switchingSequenceMonitorNotify,
179 ZonesManager::~ZonesManager()
181 LOGD("Destroying ZonesManager object...");
183 if (!mDetachOnExit) {
186 } catch (ServerException&) {
187 LOGE("Failed to stop all of the zones");
190 // wait for all tasks to complete
193 LOGD("ZonesManager object destroyed");
196 void ZonesManager::saveDynamicConfig()
198 config::saveToKVStore(mConfig.dbPath, mDynamicConfig, DB_PREFIX);
201 void ZonesManager::createZone(const std::string& zoneConfigPath)
203 LOGT("Creating Zone " << zoneConfigPath);
204 std::unique_ptr<Zone> zone(new Zone(mWorker->createSubWorker(),
207 mConfig.lxcTemplatePrefix,
208 mConfig.runMountPointPrefix));
209 const std::string id = zone->getId();
211 throw ZoneOperationException("Cannot use reserved zone ID");
214 using namespace std::placeholders;
215 zone->setNotifyActiveZoneCallback(bind(&ZonesManager::notifyActiveZoneHandler,
218 zone->setDisplayOffCallback(bind(&ZonesManager::displayOffHandler,
221 zone->setFileMoveRequestCallback(bind(&ZonesManager::handleZoneMoveFileRequest,
222 this, id, _1, _2, _3));
224 zone->setProxyCallCallback(bind(&ZonesManager::handleProxyCall,
225 this, id, _1, _2, _3, _4, _5, _6, _7));
227 zone->setDbusStateChangedCallback(bind(&ZonesManager::handleDbusStateChanged,
232 mZones.insert(ZoneMap::value_type(id, std::move(zone)));
234 // after zone is created successfully, put a file informing that zones are enabled
235 if (mZones.size() == 1) {
236 if (!utils::saveFileContent(
237 utils::createFilePath(mConfig.zonesPath, ENABLED_FILE_NAME), "")) {
238 throw ZoneOperationException(ENABLED_FILE_NAME + ": cannot create.");
243 void ZonesManager::destroyZone(const std::string& zoneId)
247 auto it = mZones.find(zoneId);
248 if (it == mZones.end()) {
249 LOGE("Failed to destroy zone " << zoneId << ": no such zone");
250 throw ZoneOperationException("No such zone");
253 // TODO give back the focus
254 it->second->setDestroyOnExit();
257 if (mZones.size() == 0) {
258 if (!utils::removeFile(utils::createFilePath(mConfig.zonesPath, ENABLED_FILE_NAME))) {
259 LOGE("Failed to remove enabled file.");
263 // update dynamic config
264 remove(mDynamicConfig.zoneConfigs, getConfigName(zoneId));
268 void ZonesManager::focus(const std::string& zoneId)
272 /* try to access the object first to throw immediately if it doesn't exist */
273 ZoneMap::mapped_type& foregroundZone = mZones.at(zoneId);
275 if (!foregroundZone->activateVT()) {
276 LOGE("Failed to activate zones VT. Aborting focus.");
280 for (auto& zone : mZones) {
281 LOGD(zone.second->getId() << ": being sent to background");
282 zone.second->goBackground();
284 mConfig.foregroundId = foregroundZone->getId();
285 LOGD(mConfig.foregroundId << ": being sent to foreground");
286 foregroundZone->goForeground();
289 void ZonesManager::startAll()
291 LOGI("Starting all zones");
295 bool isForegroundFound = false;
297 for (auto& zone : mZones) {
298 zone.second->start();
300 if (zone.first == mConfig.foregroundId) {
301 isForegroundFound = true;
302 LOGI(zone.second->getId() << ": set as the foreground zone");
303 zone.second->goForeground();
307 if (!isForegroundFound) {
308 auto foregroundIterator = std::min_element(mZones.begin(), mZones.end(),
309 [](ZoneMap::value_type &c1, ZoneMap::value_type &c2) {
310 return c1.second->getPrivilege() < c2.second->getPrivilege();
313 if (foregroundIterator != mZones.end()) {
314 mConfig.foregroundId = foregroundIterator->second->getId();
315 LOGI(mConfig.foregroundId << ": no foreground zone configured, setting one with highest priority");
316 foregroundIterator->second->goForeground();
321 void ZonesManager::stopAll()
323 LOGI("Stopping all zones");
327 for (auto& zone : mZones) {
332 bool ZonesManager::isPaused(const std::string& zoneId)
336 auto iter = mZones.find(zoneId);
337 if (iter == mZones.end()) {
338 LOGE("No such zone id: " << zoneId);
339 throw ZoneOperationException("No such zone");
342 return iter->second->isPaused();
345 bool ZonesManager::isRunning(const std::string& zoneId)
349 auto iter = mZones.find(zoneId);
350 if (iter == mZones.end()) {
351 LOGE("No such zone id: " << zoneId);
352 throw ZoneOperationException("No such zone");
354 return iter->second->isRunning();
357 std::string ZonesManager::getRunningForegroundZoneId() const
361 for (auto& zone : mZones) {
362 if (zone.first == mConfig.foregroundId &&
363 zone.second->isRunning()) {
367 return std::string();
370 std::string ZonesManager::getNextToForegroundZoneId()
374 // handles case where there is no next zone
375 if (mZones.size() < 2) {
376 return std::string();
379 for (auto it = mZones.begin(); it != mZones.end(); ++it) {
380 if (it->first == mConfig.foregroundId &&
381 it->second->isRunning()) {
382 auto nextIt = std::next(it);
383 if (nextIt != mZones.end()) {
384 return nextIt->first;
388 return mZones.begin()->first;
391 void ZonesManager::switchingSequenceMonitorNotify()
393 LOGI("switchingSequenceMonitorNotify() called");
395 auto nextZoneId = getNextToForegroundZoneId();
397 if (!nextZoneId.empty()) {
403 void ZonesManager::setZonesDetachOnExit()
407 mDetachOnExit = true;
409 for (auto& zone : mZones) {
410 zone.second->setDetachOnExit();
414 void ZonesManager::notifyActiveZoneHandler(const std::string& caller,
415 const std::string& application,
416 const std::string& message)
418 LOGI("notifyActiveZoneHandler(" << caller << ", " << application << ", " << message
424 const std::string activeZone = getRunningForegroundZoneId();
425 if (!activeZone.empty() && caller != activeZone) {
426 mZones[activeZone]->sendNotification(caller, application, message);
428 } catch(const VasumException&) {
429 LOGE("Notification from " << caller << " hasn't been sent");
433 void ZonesManager::displayOffHandler(const std::string& /*caller*/)
435 // get config of currently set zone and switch if switchToDefaultAfterTimeout is true
438 const std::string activeZoneName = getRunningForegroundZoneId();
439 const auto& activeZone = mZones.find(activeZoneName);
441 if (activeZone != mZones.end() &&
442 activeZone->second->isSwitchToDefaultAfterTimeoutAllowed()) {
443 LOGI("Switching to default zone " << mConfig.defaultId);
444 focus(mConfig.defaultId);
448 void ZonesManager::handleZoneMoveFileRequest(const std::string& srcZoneId,
449 const std::string& dstZoneId,
450 const std::string& path,
451 dbus::MethodResultBuilder::Pointer result)
453 // TODO: this implementation is only a placeholder.
454 // There are too many unanswered questions and security concerns:
455 // 1. What about mount namespace, host might not see the source/destination
456 // file. The file might be a different file from a host perspective.
457 // 2. Copy vs move (speed and security concerns over already opened FDs)
458 // 3. Access to source and destination files - DAC, uid/gig
459 // 4. Access to source and destintation files - MAC, smack
460 // 5. Destination file uid/gid assignment
461 // 6. Destination file smack label assignment
462 // 7. Verifiability of the source path
464 // NOTE: other possible implementations include:
465 // 1. Sending file descriptors opened directly in each zone through DBUS
466 // using something like g_dbus_message_set_unix_fd_list()
467 // 2. VSM forking and calling setns(MNT) in each zone and opening files
468 // by itself, then passing FDs to the main process
469 // Now when the main process has obtained FDs (by either of those methods)
470 // it can do the copying by itself.
472 LOGI("File move requested\n"
473 << "src: " << srcZoneId << "\n"
474 << "dst: " << dstZoneId << "\n"
475 << "path: " << path);
479 ZoneMap::const_iterator srcIter = mZones.find(srcZoneId);
480 if (srcIter == mZones.end()) {
481 LOGE("Source zone '" << srcZoneId << "' not found");
484 Zone& srcZone = *srcIter->second;
486 ZoneMap::const_iterator dstIter = mZones.find(dstZoneId);
487 if (dstIter == mZones.end()) {
488 LOGE("Destination zone '" << dstZoneId << "' not found");
489 result->set(g_variant_new("(s)", api::zone::FILE_MOVE_DESTINATION_NOT_FOUND.c_str()));
492 Zone& dstContanier = *dstIter->second;
494 if (srcZoneId == dstZoneId) {
495 LOGE("Cannot send a file to yourself");
496 result->set(g_variant_new("(s)", api::zone::FILE_MOVE_WRONG_DESTINATION.c_str()));
500 if (!regexMatchVector(path, srcZone.getPermittedToSend())) {
501 LOGE("Source zone has no permissions to send the file: " << path);
502 result->set(g_variant_new("(s)", api::zone::FILE_MOVE_NO_PERMISSIONS_SEND.c_str()));
506 if (!regexMatchVector(path, dstContanier.getPermittedToRecv())) {
507 LOGE("Destination zone has no permissions to receive the file: " << path);
508 result->set(g_variant_new("(s)", api::zone::FILE_MOVE_NO_PERMISSIONS_RECEIVE.c_str()));
512 namespace fs = boost::filesystem;
513 std::string srcPath = fs::absolute(srcZoneId, mConfig.zonesPath).string() + path;
514 std::string dstPath = fs::absolute(dstZoneId, mConfig.zonesPath).string() + path;
516 if (!utils::moveFile(srcPath, dstPath)) {
517 LOGE("Failed to move the file: " << path);
518 result->set(g_variant_new("(s)", api::zone::FILE_MOVE_FAILED.c_str()));
520 result->set(g_variant_new("(s)", api::zone::FILE_MOVE_SUCCEEDED.c_str()));
522 dstContanier.sendNotification(srcZoneId, path, api::zone::FILE_MOVE_SUCCEEDED);
523 } catch (ServerException&) {
524 LOGE("Notification to '" << dstZoneId << "' has not been sent");
529 void ZonesManager::handleProxyCall(const std::string& caller,
530 const std::string& target,
531 const std::string& targetBusName,
532 const std::string& targetObjectPath,
533 const std::string& targetInterface,
534 const std::string& targetMethod,
535 GVariant* parameters,
536 dbus::MethodResultBuilder::Pointer result)
538 if (!mProxyCallPolicy->isProxyCallAllowed(caller,
544 LOGW("Forbidden proxy call; " << caller << " -> " << target << "; " << targetBusName
545 << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod);
546 result->setError(api::ERROR_FORBIDDEN, "Proxy call forbidden");
550 LOGI("Proxy call; " << caller << " -> " << target << "; " << targetBusName
551 << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod);
553 auto asyncResultCallback = [result](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
555 GVariant* targetResult = asyncMethodCallResult.get();
556 result->set(g_variant_new("(v)", targetResult));
557 } catch (dbus::DbusException& e) {
558 result->setError(api::ERROR_FORWARDED, e.what());
562 if (target == HOST_ID) {
563 mHostConnection.proxyCallAsync(targetBusName,
568 asyncResultCallback);
574 ZoneMap::const_iterator targetIter = mZones.find(target);
575 if (targetIter == mZones.end()) {
576 LOGE("Target zone '" << target << "' not found");
577 result->setError(api::ERROR_INVALID_ID, "Unknown proxy call target");
581 Zone& targetZone = *targetIter->second;
582 targetZone.proxyCallAsync(targetBusName,
587 asyncResultCallback);
590 void ZonesManager::handleGetZoneDbuses(dbus::MethodResultBuilder::Pointer result) const
594 std::vector<GVariant*> entries;
595 for (auto& zone : mZones) {
596 GVariant* zoneId = g_variant_new_string(zone.first.c_str());
597 GVariant* dbusAddress = g_variant_new_string(zone.second->getDbusAddress().c_str());
598 GVariant* entry = g_variant_new_dict_entry(zoneId, dbusAddress);
599 entries.push_back(entry);
601 GVariant* dict = g_variant_new_array(G_VARIANT_TYPE("{ss}"), entries.data(), entries.size());
602 result->set(g_variant_new("(*)", dict));
605 void ZonesManager::handleDbusStateChanged(const std::string& zoneId,
606 const std::string& dbusAddress)
608 mHostConnection.signalZoneDbusState(zoneId, dbusAddress);
611 void ZonesManager::handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer result) const
615 std::vector<GVariant*> zoneIds;
616 for(auto& zone: mZones){
617 zoneIds.push_back(g_variant_new_string(zone.first.c_str()));
620 GVariant* array = g_variant_new_array(G_VARIANT_TYPE("s"),
623 result->set(g_variant_new("(*)", array));
626 void ZonesManager::handleGetActiveZoneIdCall(dbus::MethodResultBuilder::Pointer result)
628 LOGI("GetActiveZoneId call");
632 if (!mConfig.foregroundId.empty() && mZones[mConfig.foregroundId]->isRunning()){
633 result->set(g_variant_new("(s)", mConfig.foregroundId.c_str()));
635 result->set(g_variant_new("(s)", ""));
639 void ZonesManager::handleGetZoneInfoCall(const std::string& id,
640 dbus::MethodResultBuilder::Pointer result)
642 LOGI("GetZoneInfo call");
646 if (mZones.count(id) == 0) {
647 LOGE("No zone with id=" << id);
648 result->setError(api::ERROR_INVALID_ID, "No such zone id");
651 const auto& zone = mZones[id];
653 //TODO: Use the lookup map.
654 if (zone->isRunning()) {
656 } else if (zone->isStopped()) {
658 } else if (zone->isPaused()) {
661 LOGE("Unrecognized state of zone id=" << id);
662 result->setError(api::ERROR_INTERNAL, "Unrecognized state of zone");
666 result->set(g_variant_new("((siss))",
670 zone->getRootPath().c_str()));
673 void ZonesManager::handleDeclareFileCall(const std::string& zone,
675 const std::string& path,
676 const int32_t& flags,
678 dbus::MethodResultBuilder::Pointer result)
680 LOGI("DeclareFile call");
685 mZones.at(zone)->declareFile(type, path, flags, mode);
687 } catch (const std::out_of_range&) {
688 LOGE("No zone with id=" << zone);
689 result->setError(api::ERROR_INVALID_ID, "No such zone id");
690 } catch (const config::ConfigException& ex) {
691 LOGE("Can't declare file: " << ex.what());
692 result->setError(api::ERROR_INTERNAL, "Internal error");
696 void ZonesManager::handleDeclareMountCall(const std::string& source,
697 const std::string& zone,
698 const std::string& target,
699 const std::string& type,
700 const uint64_t& flags,
701 const std::string& data,
702 dbus::MethodResultBuilder::Pointer result)
704 LOGI("DeclareMount call");
709 mZones.at(zone)->declareMount(source, target, type, flags, data);
711 } catch (const std::out_of_range&) {
712 LOGE("No zone with id=" << zone);
713 result->setError(api::ERROR_INVALID_ID, "No such zone id");
714 } catch (const config::ConfigException& ex) {
715 LOGE("Can't declare mount: " << ex.what());
716 result->setError(api::ERROR_INTERNAL, "Internal error");
720 void ZonesManager::handleDeclareLinkCall(const std::string& source,
721 const std::string& zone,
722 const std::string& target,
723 dbus::MethodResultBuilder::Pointer result)
725 LOGI("DeclareLink call");
729 mZones.at(zone)->declareLink(source, target);
731 } catch (const std::out_of_range&) {
732 LOGE("No zone with id=" << zone);
733 result->setError(api::ERROR_INVALID_ID, "No such zone id");
734 } catch (const config::ConfigException& ex) {
735 LOGE("Can't declare link: " << ex.what());
736 result->setError(api::ERROR_INTERNAL, "Internal error");
740 void ZonesManager::handleSetActiveZoneCall(const std::string& id,
741 dbus::MethodResultBuilder::Pointer result)
743 LOGI("SetActiveZone call; Id=" << id );
747 auto zone = mZones.find(id);
748 if (zone == mZones.end()){
749 LOGE("No zone with id=" << id );
750 result->setError(api::ERROR_INVALID_ID, "No such zone id");
754 if (zone->second->isStopped()){
755 LOGE("Could not activate a stopped zone");
756 result->setError(api::host::ERROR_ZONE_STOPPED,
757 "Could not activate a stopped zone");
766 void ZonesManager::generateNewConfig(const std::string& id,
767 const std::string& templatePath,
768 const std::string& resultPath)
770 namespace fs = boost::filesystem;
772 if (fs::exists(resultPath)) {
773 LOGT(resultPath << " already exists, removing");
774 fs::remove(resultPath);
776 std::string resultFileDir = utils::dirName(resultPath);
777 if (!utils::createDirs(resultFileDir, fs::perms::owner_all |
778 fs::perms::group_read | fs::perms::group_exe |
779 fs::perms::others_read | fs::perms::others_exe)) {
780 LOGE("Unable to create directory for new config.");
781 throw ZoneOperationException("Unable to create directory for new config.");
786 if (!utils::readFileContent(templatePath, config)) {
787 LOGE("Failed to read template config file.");
788 throw ZoneOperationException("Failed to read template config file.");
791 std::string resultConfig = boost::regex_replace(config, ZONE_NAME_REGEX, id);
793 // generate third IP octet for network config
794 // TODO change algorithm after implementing removeZone
795 std::string thirdOctetStr = std::to_string(ZONE_IP_BASE_THIRD_OCTET + mZones.size() + 1);
796 LOGD("IP third octet: " << thirdOctetStr);
797 resultConfig = boost::regex_replace(resultConfig, ZONE_IP_THIRD_OCTET_REGEX, thirdOctetStr);
799 // generate first free VT number
800 // TODO change algorithm after implementing removeZone
801 std::string freeVT = std::to_string(ZONE_VT_BASE + mZones.size() + 1);
802 LOGD("VT number: " << freeVT);
803 resultConfig = boost::regex_replace(resultConfig, ZONE_VT_REGEX, freeVT);
805 if (!utils::saveFileContent(resultPath, resultConfig)) {
806 LOGE("Faield to save new config file.");
807 throw ZoneOperationException("Failed to save new config file.");
810 // restrict new config file so that only owner (vasum) can write it
811 fs::permissions(resultPath, fs::perms::owner_read | fs::perms::owner_write |
812 fs::perms::group_read |
813 fs::perms::others_read);
816 void ZonesManager::handleCreateZoneCall(const std::string& id,
817 dbus::MethodResultBuilder::Pointer result)
820 LOGE("Failed to add zone - invalid name.");
821 result->setError(api::ERROR_INVALID_ID, "Invalid name");
825 LOGI("Creating zone " << id);
829 // TODO: This solution is temporary. It utilizes direct access to config files when creating new
830 // zones. Update this handler when config database will appear.
831 namespace fs = boost::filesystem;
833 // check if zone does not exist
834 if (mZones.find(id) != mZones.end()) {
835 LOGE("Cannot create " << id << " zone - already exists!");
836 result->setError(api::ERROR_INVALID_ID, "Already exists");
840 const std::string zonePathStr = utils::createFilePath(mConfig.zonesPath, id, "/");
842 // copy zone image if config contains path to image
843 LOGT("Image path: " << mConfig.zoneImagePath);
844 if (!mConfig.zoneImagePath.empty()) {
845 auto copyImageContentsWrapper = std::bind(&utils::copyImageContents,
846 mConfig.zoneImagePath,
849 if (!utils::launchAsRoot(copyImageContentsWrapper)) {
850 LOGE("Failed to copy zone image.");
851 result->setError(api::ERROR_INTERNAL, "Failed to copy zone image.");
856 // generate paths to new configuration files
857 std::string newConfigName = getConfigName(id);
858 std::string newConfigPath = utils::createFilePath(mConfig.zoneNewConfigPrefix, newConfigName);
860 auto removeAllWrapper = [](const std::string& path) -> bool {
862 LOGD("Removing copied data");
863 fs::remove_all(fs::path(path));
864 } catch(const std::exception& e) {
865 LOGW("Failed to remove data: " << boost::diagnostic_information(e));
871 LOGI("Generating config from " << mConfig.zoneTemplatePath << " to " << newConfigPath);
872 generateNewConfig(id, mConfig.zoneTemplatePath, newConfigPath);
874 } catch (VasumException& e) {
875 LOGE("Generate config failed: " << e.what());
876 utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr));
877 result->setError(api::ERROR_INTERNAL, "Failed to generate config");
881 LOGT("Creating new zone");
883 createZone(newConfigPath);
884 } catch (VasumException& e) {
885 LOGE("Creating new zone failed: " << e.what());
886 utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr));
887 result->setError(api::ERROR_INTERNAL, "Failed to create zone");
891 mDynamicConfig.zoneConfigs.push_back(newConfigName);
897 void ZonesManager::handleDestroyZoneCall(const std::string& id,
898 dbus::MethodResultBuilder::Pointer result)
902 if (mZones.find(id) == mZones.end()) {
903 LOGE("Failed to destroy zone - no such zone id: " << id);
904 result->setError(api::ERROR_INVALID_ID, "No such zone id");
908 LOGI("Destroying zone " << id);
910 auto destroyer = [id, result, this] {
913 } catch (const VasumException& e) {
914 LOGE("Error during zone destruction: " << e.what());
915 result->setError(api::ERROR_INTERNAL, "Failed to destroy zone");
921 mWorker->addTask(destroyer);
924 void ZonesManager::handleShutdownZoneCall(const std::string& id,
925 dbus::MethodResultBuilder::Pointer result)
927 LOGI("ShutdownZone call; Id=" << id );
931 if (mZones.find(id) == mZones.end()) {
932 LOGE("Failed to shutdown zone - no such zone id: " << id);
933 result->setError(api::ERROR_INVALID_ID, "No such zone id");
937 LOGT("Shutdown zone " << id);
939 auto shutdown = [id, result, this] {
942 } catch (ZoneOperationException& e) {
943 LOGE("Error during zone shutdown: " << e.what());
944 result->setError(api::ERROR_INTERNAL, "Failed to shutdown zone");
950 mWorker->addTask(shutdown);
953 void ZonesManager::handleStartZoneCall(const std::string& id,
954 dbus::MethodResultBuilder::Pointer result)
956 LOGI("StartZone call; Id=" << id );
960 if (mZones.find(id) == mZones.end()) {
961 LOGE("Failed to start zone - no such zone id: " << id);
962 result->setError(api::ERROR_INVALID_ID, "No such zone id");
966 LOGT("Start zone " << id);
968 auto resultCallback = [this, id, result](bool succeeded) {
973 LOGE("Failed to start zone.");
974 result->setError(api::ERROR_INTERNAL, "Failed to start zone");
978 mZones[id]->startAsync(resultCallback);
981 void ZonesManager::handleLockZoneCall(const std::string& id,
982 dbus::MethodResultBuilder::Pointer result)
984 LOGI("LockZone call; Id=" << id );
988 auto iter = mZones.find(id);
989 if (iter == mZones.end()) {
990 LOGE("Failed to lock zone - no such zone id: " << id);
991 result->setError(api::ERROR_INVALID_ID, "No such zone id");
995 auto& zone = *iter->second;
996 if (!zone.isRunning()) {
997 LOGE("Zone id=" << id << " is not running.");
998 result->setError(api::ERROR_INVALID_STATE, "Zone is not running");
1005 } catch (ZoneOperationException& e) {
1007 result->setError(api::ERROR_INTERNAL, e.what());
1014 void ZonesManager::handleUnlockZoneCall(const std::string& id,
1015 dbus::MethodResultBuilder::Pointer result)
1017 LOGI("UnlockZone call; Id=" << id );
1021 auto iter = mZones.find(id);
1022 if (iter == mZones.end()) {
1023 LOGE("Failed to unlock zone - no such zone id: " << id);
1024 result->setError(api::ERROR_INVALID_ID, "No such zone id");
1028 auto& zone = *iter->second;
1029 if (!zone.isPaused()) {
1030 LOGE("Zone id=" << id << " is not paused.");
1031 result->setError(api::ERROR_INVALID_STATE, "Zone is not paused");
1035 LOGT("Unlock zone");
1038 } catch (ZoneOperationException& e) {
1040 result->setError(api::ERROR_INTERNAL, e.what());
1047 void ZonesManager::handleGrantDeviceCall(const std::string& id,
1048 const std::string& device,
1050 dbus::MethodResultBuilder::Pointer result)
1052 LOGI("GrantDevice call; id=" << id << "; dev=" << device);
1056 auto iter = mZones.find(id);
1057 if (iter == mZones.end()) {
1058 LOGE("Failed to grant device - no such zone id: " << id);
1059 result->setError(api::ERROR_INVALID_ID, "No such zone id");
1063 auto& zone = *iter->second;
1064 if (!zone.isRunning() && !zone.isPaused()) {
1065 LOGE("Zone id=" << id << " is not running");
1066 result->setError(api::ERROR_INVALID_STATE, "Zone is not running");
1070 std::string devicePath = "/dev/" + device;
1072 if (!lxc::isDevice(devicePath)) {
1073 LOGE("Failed to grant device - cannot acces device: " << device);
1074 result->setError(api::ERROR_FORBIDDEN, "Cannot access device");
1078 // assume device node is created inside zone
1079 if (!lxc::setDeviceAccess(id, devicePath, true, flags)) {
1080 LOGE("Failed to grant device: " << device << " for zone: " << id);
1081 result->setError(api::ERROR_INTERNAL, "Cannot grant device");
1088 void ZonesManager::handleRevokeDeviceCall(const std::string& id,
1089 const std::string& device,
1090 dbus::MethodResultBuilder::Pointer result)
1092 LOGI("RevokeDevice call; id=" << id << "; dev=" << device);
1096 auto iter = mZones.find(id);
1097 if (iter == mZones.end()) {
1098 LOGE("Failed to revoke device - no such zone id: " << id);
1099 result->setError(api::ERROR_INVALID_ID, "No such zone id");
1103 auto& zone = *iter->second;
1104 if (!zone.isRunning() && !zone.isPaused()) {
1105 LOGE("Zone id=" << id << " is not running");
1106 result->setError(api::ERROR_INVALID_STATE, "Zone is not running");
1109 std::string devicePath = "/dev/" + device;
1111 if (!lxc::isDevice(devicePath)) {
1112 LOGE("Failed to revoke device - cannot acces device: " << device);
1113 result->setError(api::ERROR_FORBIDDEN, "Cannot access device");
1117 if (!lxc::setDeviceAccess(id, devicePath, false, 0)) {
1118 LOGE("Failed to revoke device: " << device << " for zone: " << id);
1119 result->setError(api::ERROR_INTERNAL, "Cannot revoke device");
1126 } // namespace vasum