lxcpp: provisioning implementation (part 2)
[platform/core/security/vasum.git] / server / zones-manager.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Jan Olszak <j.olszak@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  Jan Olszak (j.olszak@samsung.com)
22  * @brief   Definition of the class for managing zones
23  */
24
25 #include "config.hpp"
26
27 #include "common-definitions.hpp"
28 #include "dynamic-config-scheme.hpp"
29 #include "zones-manager.hpp"
30 #include "lxc/cgroup.hpp"
31 #include "exception.hpp"
32
33 #include "utils/paths.hpp"
34 #include "logger/logger.hpp"
35 #include "config/manager.hpp"
36 #include "dbus/exception.hpp"
37 #include "utils/fs.hpp"
38 #include "utils/img.hpp"
39 #include "utils/environment.hpp"
40 #include "utils/vt.hpp"
41 #include "api/messages.hpp"
42
43 #include <boost/filesystem.hpp>
44 #include <boost/regex.hpp>
45 #include <boost/exception/diagnostic_information.hpp>
46 #include <cassert>
47 #include <string>
48 #include <climits>
49 #include <cctype>
50 #include <set>
51
52
53 namespace vasum {
54
55
56 namespace {
57
58
59 const std::string HOST_ID = "host";
60 const std::string ENABLED_FILE_NAME = "enabled";
61
62 const boost::regex ZONE_NAME_REGEX("~NAME~");
63 const boost::regex ZONE_IP_THIRD_OCTET_REGEX("~IP~");
64
65 const unsigned int ZONE_IP_BASE_THIRD_OCTET = 100;
66
67 const std::vector<std::string> prohibitedZonesNames{
68     ENABLED_FILE_NAME,
69     "lxc-monitord.log"
70 };
71
72 template<typename T>
73 void remove(std::vector<T>& v, const T& item)
74 {
75     // erase-remove idiom, ask google for explanation
76     v.erase(std::remove(v.begin(), v.end(), item), v.end());
77 }
78
79 template<typename Iter, typename Predicate>
80 Iter circularFindNext(Iter begin, Iter end, Iter current, Predicate pred)
81 {
82     if (begin == end || current == end) {
83         return end;
84     }
85     for (Iter next = current;;) {
86         ++ next;
87         if (next == end) {
88             next = begin;
89         }
90         if (next == current) {
91             return end;
92         }
93         if (pred(*next)) {
94             return next;
95         }
96     }
97 }
98
99 Zone& get(std::vector<std::unique_ptr<Zone>>::iterator iter)
100 {
101     return **iter;
102 }
103
104 bool zoneIsRunning(const std::unique_ptr<Zone>& zone) {
105     return zone->isRunning();
106 }
107
108 bool isalnum(const std::string& str)
109 {
110     for (const auto& c : str) {
111         if (!std::isalnum(c)) {
112             return false;
113         }
114     }
115     return true;
116 }
117
118 void cleanUpUnknownsFromRoot(const boost::filesystem::path& zonesPath,
119                              const std::vector<std::string>& zoneIds,
120                              bool dryRun)
121 {
122     namespace fs =  boost::filesystem;
123     const auto end = fs::directory_iterator();
124
125     std::set<std::string> knowns(zoneIds.begin(), zoneIds.end());
126     knowns.insert(prohibitedZonesNames.begin(), prohibitedZonesNames.end());
127
128     // Remove all directories that start with '.'
129     for (auto zoneDir = fs::directory_iterator(zonesPath); zoneDir != end; ++zoneDir) {
130         if (zoneDir->path().filename().string()[0] ==  '.') {
131             if (!dryRun) {
132                 fs::remove_all(zoneDir->path());
133                 LOGI("Remove directory entry: " << *zoneDir);
134             } else {
135                 LOGI("Remove directory entry (dry run): " << *zoneDir);
136             }
137         }
138     }
139
140     for (auto zoneDir = fs::directory_iterator(zonesPath); zoneDir != end; ++zoneDir) {
141         const auto zoneIt = knowns.find(zoneDir->path().filename().string());
142         if (zoneIt == knowns.end()) {
143             if (!dryRun) {
144                 const std::string filename = '.' + zoneDir->path().filename().string();
145                 fs::path newName = zoneDir->path().parent_path() / filename;
146
147                 fs::rename(zoneDir->path(), newName);
148                 fs::remove_all(newName);
149                 LOGI("Remove directory entry: " << *zoneDir);
150             } else {
151                 LOGI("Remove directory entry (dry run): " << *zoneDir);
152             }
153         }
154     }
155 }
156
157 } // namespace
158
159
160 ZonesManager::ZonesManager(ipc::epoll::EventPoll& eventPoll, const std::string& configPath)
161     : mIsRunning(true)
162     , mWorker(utils::Worker::create())
163     , mDetachOnExit(false)
164     , mExclusiveIDLock(INVALID_CONNECTION_ID)
165     , mHostIPCConnection(eventPoll, this)
166 #ifdef DBUS_CONNECTION
167     , mHostDbusConnection(this)
168 #endif
169 {
170     LOGD("Instantiating ZonesManager object...");
171
172     config::loadFromJsonFile(configPath, mConfig);
173     config::loadFromKVStoreWithJsonFile(mConfig.dbPath,
174                                         configPath,
175                                         mDynamicConfig,
176                                         getVasumDbPrefix());
177
178     if (mConfig.inputConfig.enabled) {
179         LOGI("Registering input monitor [" << mConfig.inputConfig.device.c_str() << "]");
180         mSwitchingSequenceMonitor.reset(new InputMonitor(eventPoll, mConfig.inputConfig, this));
181     }
182 }
183
184 ZonesManager::~ZonesManager()
185 {
186     LOGD("Destroying ZonesManager object...");
187     stop(true);
188 }
189
190 void ZonesManager::start()
191 {
192     Lock lock(mMutex);
193
194     LOGD("Starting ZonesManager");
195
196     mIsRunning = true;
197
198     cleanUpUnknownsFromRoot(mConfig.zonesPath, mDynamicConfig.zoneIds, !mConfig.cleanUpZonesPath);
199
200 #ifdef DBUS_CONNECTION
201     using namespace std::placeholders;
202     mProxyCallPolicy.reset(new ProxyCallPolicy(mConfig.proxyCallRules));
203     mHostDbusConnection.setProxyCallCallback(std::bind(&ZonesManager::handleProxyCall,
204                                                        this, HOST_ID, _1, _2, _3, _4, _5, _6, _7));
205 #endif //DBUS_CONNECTION
206
207     for (const auto& zoneId : mDynamicConfig.zoneIds) {
208         insertZone(zoneId, getTemplatePathForExistingZone(zoneId));
209     }
210
211     updateDefaultId();
212
213     LOGD("ZonesManager object instantiated");
214
215     if (mConfig.inputConfig.enabled) {
216         LOGI("Starting input monitor ");
217         mSwitchingSequenceMonitor->start();
218     }
219
220     // After everything's initialized start to respond to clients' requests
221     mHostIPCConnection.start();
222 }
223
224 void ZonesManager::stop(bool wait)
225 {
226     Lock lock(mMutex);
227     LOGD("Stopping ZonesManager");
228
229     if(!mIsRunning) {
230         return;
231     }
232
233     if (!mDetachOnExit) {
234         try {
235             shutdownAll();
236         } catch (ServerException&) {
237             LOGE("Failed to shutdown all of the zones");
238         }
239     }
240
241     // wait for all tasks to complete
242     mWorker.reset();
243     mHostIPCConnection.stop(wait);
244     if (mConfig.inputConfig.enabled) {
245         LOGI("Stopping input monitor ");
246         mSwitchingSequenceMonitor->stop();
247     }
248     mIsRunning = false;
249 }
250
251 bool ZonesManager::isRunning()
252 {
253     Lock lock(mMutex);
254     return mIsRunning ||  mHostIPCConnection.isRunning();
255 }
256
257 ZonesManager::Zones::iterator ZonesManager::findZone(const std::string& id)
258 {
259     return std::find_if(mZones.begin(), mZones.end(), [&id](const std::unique_ptr<Zone>& zone) {
260         return zone->getId() == id;
261     });
262 }
263
264 Zone& ZonesManager::getZone(const std::string& id)
265 {
266     auto iter = findZone(id);
267     if (iter == mZones.end()) {
268         throw InvalidZoneIdException("Zone id not found");
269     }
270     return get(iter);
271 }
272
273 void ZonesManager::saveDynamicConfig()
274 {
275     config::saveToKVStore(mConfig.dbPath, mDynamicConfig, getVasumDbPrefix());
276 }
277
278 void ZonesManager::updateDefaultId()
279 {
280     // TODO add an api to change defaultId
281     if (mZones.empty() && mDynamicConfig.defaultId.empty()) {
282         LOGT("Keep empty defaultId");
283         return;
284     }
285     if (findZone(mDynamicConfig.defaultId) != mZones.end()) {
286         LOGT("Keep " << mDynamicConfig.defaultId << " as defaultId");
287         return;
288     }
289
290     // update
291     if (mZones.empty()) {
292         mDynamicConfig.defaultId.clear();
293         LOGD("DefaultId cleared");
294     } else {
295         mDynamicConfig.defaultId = mZones.front()->getId();
296         LOGD("DefaultId changed to " << mDynamicConfig.defaultId);
297     }
298     saveDynamicConfig();
299 }
300
301 std::string ZonesManager::getTemplatePathForExistingZone(const std::string& id)
302 {
303     ZoneTemplatePathConfig config;
304     config::loadFromKVStore(mConfig.dbPath, config, getZoneDbPrefix(id));
305     return config.zoneTemplatePath;
306 }
307
308 void ZonesManager::insertZone(const std::string& zoneId, const std::string& zoneTemplatePath)
309 {
310     if (zoneId == HOST_ID) {
311         throw InvalidZoneIdException("Cannot use reserved zone ID");
312     }
313     if (findZone(zoneId) != mZones.end()) {
314         throw InvalidZoneIdException("Zone already exists");
315     }
316
317     LOGT("Creating Zone " << zoneId);
318     std::unique_ptr<Zone> zone(new Zone(zoneId,
319                                         mConfig.zonesPath,
320                                         zoneTemplatePath,
321                                         mConfig.dbPath,
322                                         mConfig.zoneTemplateDir,
323                                         mConfig.runMountPointPrefix));
324
325     mZones.push_back(std::move(zone));
326
327     // after zone is created successfully, put a file informing that zones are enabled
328     if (mZones.size() == 1) {
329         if (!utils::saveFileContent(
330                 utils::createFilePath(mConfig.zonesPath, ENABLED_FILE_NAME), "")) {
331             throw ZoneOperationException(ENABLED_FILE_NAME + ": cannot create.");
332         }
333     }
334 }
335
336 void ZonesManager::tryAddTask(const utils::Worker::Task& task, api::MethodResultBuilder::Pointer result, bool wait)
337 {
338     {
339         Lock lock(mExclusiveIDMutex);
340
341         if (mExclusiveIDLock != INVALID_CONNECTION_ID &&
342             mExclusiveIDLock != result->getID()) {
343             result->setError(api::ERROR_QUEUE, "Queue is locked by another client");
344             return;
345         }
346     }
347
348     if (wait) {
349         mWorker->addTaskAndWait(task);
350     } else {
351         mWorker->addTask(task);
352     }
353 }
354
355 void ZonesManager::destroyZone(const std::string& zoneId)
356 {
357     Lock lock(mMutex);
358
359     auto iter = findZone(zoneId);
360     if (iter == mZones.end()) {
361         const std::string msg = "Failed to destroy zone " + zoneId + ": no such zone";
362         LOGE(msg);
363         throw InvalidZoneIdException(msg);
364     }
365
366     get(iter).setDestroyOnExit();
367     mZones.erase(iter);
368
369     if (mZones.empty()) {
370         if (!utils::removeFile(utils::createFilePath(mConfig.zonesPath, ENABLED_FILE_NAME))) {
371             LOGE("Failed to remove enabled file.");
372         }
373     }
374
375     // update dynamic config
376     remove(mDynamicConfig.zoneIds, zoneId);
377     saveDynamicConfig();
378     updateDefaultId();
379
380     refocus();
381 }
382
383 void ZonesManager::focus(const std::string& zoneId)
384 {
385     Lock lock(mMutex);
386     auto iter = findZone(zoneId);
387     focusInternal(iter);
388 }
389
390 void ZonesManager::focusInternal(Zones::iterator iter)
391 {
392     // assume mutex is locked
393     if (iter == mZones.end()) {
394         if (!mActiveZoneId.empty()) {
395             LOGI("Focus to: host");
396             utils::activateVT(mConfig.hostVT);
397             mActiveZoneId.clear();
398         }
399         return;
400     }
401
402     Zone& zoneToFocus = get(iter);
403     const std::string& idToFocus = zoneToFocus.getId();
404
405     if (idToFocus == mActiveZoneId) {
406         return;
407     }
408
409     if (!zoneToFocus.isRunning()) {
410         LOGE("Can't focus not running zone " << idToFocus);
411         assert(false);
412         return;
413     }
414
415     LOGI("Focus to: " << idToFocus);
416
417     if (!zoneToFocus.activateVT()) {
418         LOGE("Failed to activate zones VT");
419         return;
420     }
421
422     for (auto& zone : mZones) {
423         if (zone->isRunning()) {
424             std::string id = zone->getId();
425             if (id == idToFocus) {
426                 LOGD(id << ": being sent to foreground");
427                 zone->goForeground();
428             } else {
429                 LOGD(id << ": being sent to background");
430                 zone->goBackground();
431             }
432         }
433     }
434     mActiveZoneId = idToFocus;
435 }
436
437 void ZonesManager::refocus()
438 {
439     // assume mutex is locked
440
441     // check if refocus is required
442     auto oldIter = findZone(mActiveZoneId);
443     if (oldIter != mZones.end() && get(oldIter).isRunning()) {
444         return;
445     }
446
447     // try to refocus to defaultId
448     auto iter = findZone(mDynamicConfig.defaultId);
449     if (iter == mZones.end() || !get(iter).isRunning()) {
450         // focus to any running or to host if not found
451         iter = std::find_if(mZones.begin(), mZones.end(), zoneIsRunning);
452     }
453     focusInternal(iter);
454 }
455
456 void ZonesManager::restoreAll()
457 {
458     LOGI("Restoring all zones");
459
460     Lock lock(mMutex);
461
462     for (auto& zone : mZones) {
463         zone->restore();
464     }
465
466     refocus();
467 }
468
469 void ZonesManager::shutdownAll()
470 {
471     LOGI("Stopping all zones");
472
473     Lock lock(mMutex);
474
475     for (auto& zone : mZones) {
476         zone->stop(false);
477     }
478
479     refocus();
480 }
481
482 bool ZonesManager::isPaused(const std::string& zoneId)
483 {
484     Lock lock(mMutex);
485     return getZone(zoneId).isPaused();
486 }
487
488 bool ZonesManager::isRunning(const std::string& zoneId)
489 {
490     Lock lock(mMutex);
491     return getZone(zoneId).isRunning();
492 }
493
494 bool ZonesManager::isStopped(const std::string& zoneId)
495 {
496     Lock lock(mMutex);
497     return getZone(zoneId).isStopped();
498 }
499
500 std::string ZonesManager::getRunningForegroundZoneId()
501 {
502     Lock lock(mMutex);
503     auto iter = getRunningForegroundZoneIterator();
504     return iter == mZones.end() ? std::string() : get(iter).getId();
505 }
506
507 std::string ZonesManager::getNextToForegroundZoneId()
508 {
509     Lock lock(mMutex);
510     auto iter = getNextToForegroundZoneIterator();
511     return iter == mZones.end() ? std::string() : get(iter).getId();
512 }
513
514 ZonesManager::Zones::iterator ZonesManager::getRunningForegroundZoneIterator()
515 {
516     // assume mutex is locked
517     if (mActiveZoneId.empty()) {
518         return mZones.end();
519     }
520     auto iter = findZone(mActiveZoneId);
521     if (!get(iter).isRunning()) {
522         LOGW("Active zone " << mActiveZoneId << " is not running any more!");
523         return mZones.end();
524     }
525     return iter;
526 }
527
528 ZonesManager::Zones::iterator ZonesManager::getNextToForegroundZoneIterator()
529 {
530     // assume mutex is locked
531     auto current = findZone(mActiveZoneId);
532     if (current == mZones.end()) {
533         // find any running
534         return std::find_if(mZones.begin(), mZones.end(), zoneIsRunning);
535     } else {
536         // find next running
537         return circularFindNext(mZones.begin(), mZones.end(), current, zoneIsRunning);
538     }
539 }
540
541 void ZonesManager::switchingSequenceMonitorNotify()
542 {
543     LOGI("switchingSequenceMonitorNotify() called");
544
545     Lock lock(mMutex);
546
547     auto next = getNextToForegroundZoneIterator();
548
549     if (next != mZones.end()) {
550         focusInternal(next);
551     }
552 }
553
554
555 void ZonesManager::setZonesDetachOnExit()
556 {
557     Lock lock(mMutex);
558
559     mDetachOnExit = true;
560
561     for (auto& zone : mZones) {
562         zone->setDetachOnExit();
563     }
564 }
565
566 void ZonesManager::disconnectedCallback(const std::string& id)
567 {
568     LOGD("Client Disconnected: " << id);
569
570     {
571         Lock lock(mExclusiveIDMutex);
572
573         if (mExclusiveIDLock == id) {
574             mExclusiveIDLock = INVALID_CONNECTION_ID;
575         }
576     }
577 }
578
579 void ZonesManager::handleSwitchToDefaultCall(const std::string& /*caller*/,
580                                              api::MethodResultBuilder::Pointer result)
581 {
582     auto handler = [&, this] {
583         // get config of currently set zone and switch if switchToDefaultAfterTimeout is true
584         Lock lock(mMutex);
585
586         auto activeIter = findZone(mActiveZoneId);
587         auto defaultIter = findZone(mDynamicConfig.defaultId);
588
589         if (activeIter != mZones.end() &&
590             defaultIter != mZones.end() &&
591             get(activeIter).isSwitchToDefaultAfterTimeoutAllowed() &&
592             get(defaultIter).isRunning()) {
593
594             LOGI("Switching to default zone " << mDynamicConfig.defaultId);
595             focusInternal(defaultIter);
596         }
597         result->setVoid();
598     };
599
600     tryAddTask(handler, result, true);
601 }
602
603 void ZonesManager::handleCreateFileCall(const api::CreateFileIn& request,
604                                         api::MethodResultBuilder::Pointer result)
605 {
606     auto handler = [&, this] {
607         LOGI("CreateFile call");
608
609         Lock lock(mMutex);
610
611         auto srcIter = findZone(request.id);
612         if (srcIter == mZones.end()) {
613             LOGE("Zone '" << request.id << "' not found");
614             result->setError(api::ERROR_INVALID_ID, "Requested Zone was not found.");
615             return;
616         }
617         Zone& srcZone = get(srcIter);
618
619         auto retValue = std::make_shared<api::CreateFileOut>();
620         try {
621             retValue->fd = srcZone.createFile(request.path, request.flags, request.mode);
622         } catch(ZoneOperationException& e) {
623             result->setError(api::ERROR_CREATE_FILE_FAILED, "Unable to create file");
624             return;
625         }
626
627         result->set(retValue);
628     };
629
630     tryAddTask(handler, result, true);
631 }
632
633 #ifdef DBUS_CONNECTION
634 void ZonesManager::handleProxyCall(const std::string& caller,
635                                    const std::string& target,
636                                    const std::string& targetBusName,
637                                    const std::string& targetObjectPath,
638                                    const std::string& targetInterface,
639                                    const std::string& targetMethod,
640                                    GVariant* parameters,
641                                    dbus::MethodResultBuilder::Pointer result)
642 {
643     auto handler = [&, this] {
644         if (!mProxyCallPolicy->isProxyCallAllowed(caller,
645                                                   target,
646                                                   targetBusName,
647                                                   targetObjectPath,
648                                                   targetInterface,
649                                                   targetMethod)) {
650             LOGW("Forbidden proxy call; " << caller << " -> " << target << "; " << targetBusName
651                  << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod);
652             result->setError(api::ERROR_FORBIDDEN, "Proxy call forbidden");
653             return;
654         }
655
656         LOGI("Proxy call; " << caller << " -> " << target << "; " << targetBusName
657              << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod);
658
659         auto asyncResultCallback = [result](dbus::AsyncMethodCallResult & asyncMethodCallResult) {
660             try {
661                 GVariant* targetResult = asyncMethodCallResult.get();
662                 result->set(g_variant_new("(v)", targetResult));
663             } catch (dbus::DbusException& e) {
664                 result->setError(api::ERROR_FORWARDED, e.what());
665             }
666         };
667
668         if (target != HOST_ID) {
669             result->setError(api::ERROR_INVALID_ID, "Unknown proxy call target");
670             return;
671         }
672
673         mHostDbusConnection.proxyCallAsync(targetBusName,
674                                            targetObjectPath,
675                                            targetInterface,
676                                            targetMethod,
677                                            parameters,
678                                            asyncResultCallback);
679     };
680
681     // This call cannot be locked by lock/unlock queue
682     mWorker->addTaskAndWait(handler);
683 }
684 #endif //DBUS_CONNECTION
685
686 void ZonesManager::handleLockQueueCall(api::MethodResultBuilder::Pointer result)
687 {
688     Lock lock(mExclusiveIDMutex);
689     std::string id = result->getID();
690
691     LOGI("Lock Queue: " << id);
692
693     if (mExclusiveIDLock == id) {
694         result->setError(api::ERROR_QUEUE, "Queue already locked");
695         return;
696     }
697
698     if (mExclusiveIDLock != INVALID_CONNECTION_ID) {
699         result->setError(api::ERROR_QUEUE, "Queue locked by another connection");
700         return;
701     }
702
703     mExclusiveIDLock = id;
704     result->setVoid();
705 }
706
707 void ZonesManager::handleUnlockQueueCall(api::MethodResultBuilder::Pointer result)
708 {
709     Lock lock(mExclusiveIDMutex);
710     std::string id = result->getID();
711
712     LOGI("Unlock Queue: " << id);
713
714     if (mExclusiveIDLock == INVALID_CONNECTION_ID) {
715         result->setError(api::ERROR_QUEUE, "Queue not locked");
716         return;
717     }
718
719     if (mExclusiveIDLock != id) {
720         result->setError(api::ERROR_QUEUE, "Queue locked by another connection");
721         return;
722     }
723
724     mExclusiveIDLock = INVALID_CONNECTION_ID;
725     result->setVoid();
726 }
727
728 void ZonesManager::handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result)
729 {
730     auto handler = [&, this] {
731         LOGI("GetZoneIds call");
732
733         Lock lock(mMutex);
734
735         auto zoneIds = std::make_shared<api::ZoneIds>();
736         for (const auto& zone : mZones) {
737             zoneIds->values.push_back(zone->getId());
738         }
739
740         result->set(zoneIds);
741     };
742
743     // This call cannot be locked by lock/unlock queue
744     mWorker->addTaskAndWait(handler);
745 }
746
747 void ZonesManager::handleGetActiveZoneIdCall(api::MethodResultBuilder::Pointer result)
748 {
749     auto handler = [&, this] {
750         LOGI("GetActiveZoneId call");
751
752         auto zoneId = std::make_shared<api::ZoneId>();
753         zoneId->value = getRunningForegroundZoneId();
754         result->set(zoneId);
755     };
756
757     // This call cannot be locked by lock/unlock queue
758     mWorker->addTaskAndWait(handler);
759 }
760
761 void ZonesManager::handleGetZoneInfoCall(const api::ZoneId& zoneId,
762                                          api::MethodResultBuilder::Pointer result)
763 {
764     auto handler = [&, this] {
765         LOGI("GetZoneInfo call");
766
767         Lock lock(mMutex);
768
769         auto iter = findZone(zoneId.value);
770         if (iter == mZones.end()) {
771             LOGE("No zone with id=" << zoneId.value);
772             result->setError(api::ERROR_INVALID_ID, "No such zone id");
773             return;
774         }
775
776         Zone& zone = get(iter);
777         auto zoneInfo = std::make_shared<api::ZoneInfoOut>();
778
779         if (zone.isRunning()) {
780             zoneInfo->state = "RUNNING";
781         } else if (zone.isStopped()) {
782             zoneInfo->state = "STOPPED";
783         } else if (zone.isPaused()) {
784             zoneInfo->state = "FROZEN";
785         } else {
786             LOGE("Unrecognized state of zone id=" << zoneId.value);
787             result->setError(api::ERROR_INTERNAL, "Unrecognized state of zone");
788             return;
789         }
790
791         zoneInfo->id = zone.getId();
792         zoneInfo->vt = zone.getVT();
793         zoneInfo->rootPath = zone.getRootPath();
794         result->set(zoneInfo);
795     };
796
797     // This call cannot be locked by lock/unlock queue
798     mWorker->addTaskAndWait(handler);
799 }
800
801 void ZonesManager::handleSetNetdevAttrsCall(const api::SetNetDevAttrsIn& data,
802                                             api::MethodResultBuilder::Pointer result)
803 {
804     auto handler = [&, this] {
805         LOGI("SetNetdevAttrs call");
806
807         try {
808             Lock lock(mMutex);
809
810             // TODO: Use vector<StringPair> instead of tuples
811             std::vector<std::tuple<std::string, std::string>> attrsAsTuples;
812             for(const auto& entry: data.attrs){
813                 attrsAsTuples.push_back(std::make_tuple(entry.first, entry.second));
814             }
815
816             getZone(data.id).setNetdevAttrs(data.netDev, attrsAsTuples);
817             result->setVoid();
818         } catch (const InvalidZoneIdException&) {
819             LOGE("No zone with id=" << data.id);
820             result->setError(api::ERROR_INVALID_ID, "No such zone id");
821         } catch (const std::runtime_error& ex) {
822             LOGE("Can't set attributes: " << ex.what());
823             result->setError(api::ERROR_INTERNAL, ex.what());
824         }
825     };
826
827     tryAddTask(handler, result, true);
828 }
829
830 void ZonesManager::handleGetNetdevAttrsCall(const api::GetNetDevAttrsIn& data,
831                                             api::MethodResultBuilder::Pointer result)
832 {
833     auto handler = [&, this] {
834         LOGI("GetNetdevAttrs call");
835
836         try {
837             Lock lock(mMutex);
838             auto netDevAttrs = std::make_shared<api::GetNetDevAttrs>();
839             const auto attrs = getZone(data.first).getNetdevAttrs(data.second);
840
841             for (size_t i = 0; i < attrs.size(); ++i) {
842                 netDevAttrs->values.push_back({std::get<0>(attrs[i]), std::get<1>(attrs[i])});
843             }
844             result->set(netDevAttrs);
845         } catch (const InvalidZoneIdException&) {
846             LOGE("No zone with id=" << data.first);
847             result->setError(api::ERROR_INVALID_ID, "No such zone id");
848         } catch (const std::runtime_error& ex) {
849             LOGE("Can't set attributes: " << ex.what());
850             result->setError(api::ERROR_INTERNAL, ex.what());
851         }
852     };
853
854     tryAddTask(handler, result, true);
855 }
856
857 void ZonesManager::handleGetNetdevListCall(const api::ZoneId& zoneId,
858                                            api::MethodResultBuilder::Pointer result)
859 {
860     auto handler = [&, this] {
861         LOGI("GetNetdevList call");
862
863         try {
864             Lock lock(mMutex);
865             auto netDevList = std::make_shared<api::NetDevList>();
866             netDevList->values = getZone(zoneId.value).getNetdevList();
867             result->set(netDevList);
868         } catch (const InvalidZoneIdException&) {
869             LOGE("No zone with id=" << zoneId.value);
870             result->setError(api::ERROR_INVALID_ID, "No such zone id");
871         } catch (const std::runtime_error& ex) {
872             LOGE("Can't set attributes: " << ex.what());
873             result->setError(api::ERROR_INTERNAL, ex.what());
874         }
875     };
876
877     tryAddTask(handler, result, true);
878 }
879
880 void ZonesManager::handleCreateNetdevVethCall(const api::CreateNetDevVethIn& data,
881                                               api::MethodResultBuilder::Pointer result)
882 {
883     auto handler = [&, this] {
884         LOGI("CreateNetdevVeth call");
885
886         try {
887             Lock lock(mMutex);
888
889             getZone(data.id).createNetdevVeth(data.zoneDev, data.hostDev);
890             result->setVoid();
891         } catch (const InvalidZoneIdException&) {
892             LOGE("No zone with id=" << data.id);
893             result->setError(api::ERROR_INVALID_ID, "No such zone id");
894         } catch (const std::runtime_error& ex) {
895             LOGE("Can't create veth: " << ex.what());
896             result->setError(api::ERROR_INTERNAL, ex.what());
897         }
898     };
899
900     tryAddTask(handler, result, true);
901 }
902
903 void ZonesManager::handleCreateNetdevMacvlanCall(const api::CreateNetDevMacvlanIn& data,
904                                                  api::MethodResultBuilder::Pointer result)
905 {
906     auto handler = [&, this] {
907         LOGI("CreateNetdevMacvlan call");
908
909         try {
910             Lock lock(mMutex);
911             getZone(data.id).createNetdevMacvlan(data.zoneDev, data.hostDev, data.mode);
912             result->setVoid();
913         } catch (const InvalidZoneIdException&) {
914             LOGE("No zone with id=" << data.id);
915             result->setError(api::ERROR_INVALID_ID, "No such zone id");
916         } catch (const std::runtime_error& ex) {
917             LOGE("Can't create macvlan: " << ex.what());
918             result->setError(api::ERROR_INTERNAL, ex.what());
919         }
920     };
921
922     tryAddTask(handler, result, true);
923 }
924
925 void ZonesManager::handleCreateNetdevPhysCall(const api::CreateNetDevPhysIn& data,
926                                               api::MethodResultBuilder::Pointer result)
927 {
928     auto handler = [&, this] {
929         LOGI("CreateNetdevPhys call");
930
931         try {
932             Lock lock(mMutex);
933
934             getZone(data.first).moveNetdev(data.second);
935             result->setVoid();
936         } catch (const InvalidZoneIdException&) {
937             LOGE("No zone with id=" << data.first);
938             result->setError(api::ERROR_INVALID_ID, "No such zone id");
939         } catch (const std::runtime_error& ex) {
940             LOGE("Can't create netdev: " << ex.what());
941             result->setError(api::ERROR_INTERNAL, ex.what());
942         }
943     };
944
945     tryAddTask(handler, result, true);
946 }
947
948 void ZonesManager::handleDestroyNetdevCall(const api::DestroyNetDevIn& data,
949                                            api::MethodResultBuilder::Pointer result)
950 {
951     auto handler = [&, this] {
952         LOGI("DestroyNetdev call");
953
954         try {
955             Lock lock(mMutex);
956
957             getZone(data.first).destroyNetdev(data.second);
958             result->setVoid();
959         } catch (const InvalidZoneIdException&) {
960             LOGE("No zone with id=" << data.first);
961             result->setError(api::ERROR_INVALID_ID, "No such zone id");
962         } catch (const std::runtime_error& ex) {
963             LOGE("Can't create netdev: " << ex.what());
964             result->setError(api::ERROR_INTERNAL, ex.what());
965         }
966     };
967
968     tryAddTask(handler, result, true);
969 }
970
971 void ZonesManager::handleDeleteNetdevIpAddressCall(const api::DeleteNetdevIpAddressIn& data,
972                                                    api::MethodResultBuilder::Pointer result)
973 {
974     auto handler = [&, this] {
975         LOGI("DelNetdevIpAddress call");
976
977         try {
978             Lock lock(mMutex);
979             getZone(data.zone).deleteNetdevIpAddress(data.netdev, data.ip);
980             result->setVoid();
981         } catch (const InvalidZoneIdException&) {
982             LOGE("No zone with id=" << data.zone);
983             result->setError(api::ERROR_INVALID_ID, "No such zone id");
984         } catch (const std::runtime_error& ex) {
985             LOGE("Can't delete address: " << ex.what());
986             result->setError(api::ERROR_INTERNAL, ex.what());
987         }
988     };
989
990     tryAddTask(handler, result, true);
991 }
992
993 void ZonesManager::handleDeclareFileCall(const api::DeclareFileIn& data,
994                                          api::MethodResultBuilder::Pointer result)
995 {
996     auto handler = [&, this] {
997         LOGI("DeclareFile call");
998
999         try {
1000             Lock lock(mMutex);
1001             auto declaration = std::make_shared<api::Declaration>();
1002             declaration->value = getZone(data.zone).declareFile(data.type, data.path, data.flags, data.mode);
1003             result->set(declaration);
1004         } catch (const InvalidZoneIdException&) {
1005             LOGE("No zone with id=" << data.zone);
1006             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1007         } catch (const config::ConfigException& ex) {
1008             LOGE("Can't declare file: " << ex.what());
1009             result->setError(api::ERROR_INTERNAL, "Internal error");
1010         }
1011     };
1012
1013     tryAddTask(handler, result, true);
1014 }
1015
1016 void ZonesManager::handleDeclareMountCall(const api::DeclareMountIn& data,
1017                                           api::MethodResultBuilder::Pointer result)
1018 {
1019     auto handler = [&, this] {
1020         LOGI("DeclareMount call");
1021
1022         try {
1023             Lock lock(mMutex);
1024             auto declaration = std::make_shared<api::Declaration>();
1025             declaration->value = getZone(data.zone).declareMount(data.source, data.target, data.type, data.flags, data.data);
1026             result->set(declaration);
1027         } catch (const InvalidZoneIdException&) {
1028             LOGE("No zone with id=" << data.zone);
1029             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1030         } catch (const config::ConfigException& ex) {
1031             LOGE("Can't declare mount: " << ex.what());
1032             result->setError(api::ERROR_INTERNAL, "Internal error");
1033         }
1034     };
1035
1036     tryAddTask(handler, result, true);
1037 }
1038
1039 void ZonesManager::handleDeclareLinkCall(const api::DeclareLinkIn& data,
1040                                          api::MethodResultBuilder::Pointer result)
1041 {
1042     auto handler = [&, this] {
1043         LOGI("DeclareLink call");
1044
1045         try {
1046             Lock lock(mMutex);
1047             auto declaration = std::make_shared<api::Declaration>();
1048             declaration->value = getZone(data.zone).declareLink(data.source, data.target);
1049             result->set(declaration);
1050         } catch (const InvalidZoneIdException&) {
1051             LOGE("No zone with id=" << data.zone);
1052             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1053         } catch (const config::ConfigException& ex) {
1054             LOGE("Can't declare link: " << ex.what());
1055             result->setError(api::ERROR_INTERNAL, "Internal error");
1056         }
1057     };
1058
1059     tryAddTask(handler, result, true);
1060 }
1061
1062 void ZonesManager::handleGetDeclarationsCall(const api::ZoneId& zoneId,
1063                                              api::MethodResultBuilder::Pointer result)
1064 {
1065     auto handler = [&, this] {
1066         LOGI("GetDeclarations call Id=" << zoneId.value);
1067
1068         try {
1069             Lock lock(mMutex);
1070             auto declarations = std::make_shared<api::Declarations>();
1071             declarations->values = getZone(zoneId.value).getDeclarations();
1072             result->set(declarations);
1073         } catch (const InvalidZoneIdException&) {
1074             LOGE("No zone with id=" << zoneId.value);
1075             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1076         } catch (const std::runtime_error& ex) {
1077             LOGE(ex.what());
1078             result->setError(api::ERROR_INTERNAL, ex.what());
1079         }
1080     };
1081
1082     tryAddTask(handler, result, true);
1083 }
1084
1085 void ZonesManager::handleRemoveDeclarationCall(const api::RemoveDeclarationIn& data,
1086                                                api::MethodResultBuilder::Pointer result)
1087 {
1088     auto handler = [&, this] {
1089         LOGI("RemoveDeclaration call Id=" << data.first);
1090
1091         try {
1092             Lock lock(mMutex);
1093             getZone(data.first).removeDeclaration(data.second);
1094             result->setVoid();
1095         } catch (const InvalidZoneIdException&) {
1096             LOGE("No zone with id=" << data.first);
1097             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1098         } catch (const std::runtime_error& ex) {
1099             LOGE(ex.what());
1100             result->setError(api::ERROR_INTERNAL, ex.what());
1101         }
1102     };
1103
1104     tryAddTask(handler, result, true);
1105 }
1106
1107 void ZonesManager::handleSetActiveZoneCall(const api::ZoneId& zoneId,
1108                                            api::MethodResultBuilder::Pointer result)
1109 {
1110     auto handler = [&, this] {
1111         LOGI("SetActiveZone call; Id=" << zoneId.value );
1112
1113         Lock lock(mMutex);
1114
1115         auto iter = findZone(zoneId.value);
1116         if (iter == mZones.end()) {
1117             LOGE("No zone with id=" << zoneId.value);
1118             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1119             return;
1120         }
1121
1122         if (!get(iter).isRunning()) {
1123             LOGE("Could not activate stopped or paused zone");
1124             result->setError(api::ERROR_ZONE_NOT_RUNNING,
1125                              "Could not activate stopped or paused zone");
1126             return;
1127         }
1128
1129         focusInternal(iter);
1130         result->setVoid();
1131     };
1132
1133     tryAddTask(handler, result, true);
1134 }
1135
1136
1137 void ZonesManager::generateNewConfig(const std::string& id,
1138                                      const std::string& templatePath)
1139 {
1140     const std::string dbPrefix = getZoneDbPrefix(id);
1141     ZoneDynamicConfig dynamicConfig;
1142     config::loadFromKVStoreWithJsonFile(mConfig.dbPath, templatePath, dynamicConfig, dbPrefix);
1143
1144     // update mount point path
1145     dynamicConfig.runMountPoint = boost::regex_replace(dynamicConfig.runMountPoint,
1146                                                        ZONE_NAME_REGEX,
1147                                                        id);
1148
1149     if (dynamicConfig.vt >= 0) {
1150         // generate first free VT number
1151         const int freeVT = getVTForNewZone();
1152         LOGD("VT number: " << freeVT);
1153         dynamicConfig.vt = freeVT;
1154
1155         if (!dynamicConfig.ipv4Gateway.empty() && !dynamicConfig.ipv4.empty()) {
1156             // generate third IP octet for network config
1157             std::string thirdOctetStr = std::to_string(ZONE_IP_BASE_THIRD_OCTET + freeVT);
1158             LOGD("IP third octet: " << thirdOctetStr);
1159             dynamicConfig.ipv4Gateway = boost::regex_replace(dynamicConfig.ipv4Gateway,
1160                                                              ZONE_IP_THIRD_OCTET_REGEX,
1161                                                              thirdOctetStr);
1162             dynamicConfig.ipv4 = boost::regex_replace(dynamicConfig.ipv4,
1163                                                       ZONE_IP_THIRD_OCTET_REGEX,
1164                                                       thirdOctetStr);
1165         }
1166     }
1167
1168     // save dynamic config
1169     config::saveToKVStore(mConfig.dbPath, dynamicConfig, dbPrefix);
1170
1171     // save zone template path
1172     ZoneTemplatePathConfig templatePathConfig;
1173     templatePathConfig.zoneTemplatePath = templatePath;
1174     config::saveToKVStore(mConfig.dbPath, templatePathConfig, dbPrefix);
1175
1176 }
1177
1178 int ZonesManager::getVTForNewZone()
1179 {
1180     if (mConfig.availableVTs.empty()) {
1181         return -1;
1182     }
1183     std::set<int> candidates(mConfig.availableVTs.begin(), mConfig.availableVTs.end());
1184     // exclude all used
1185     for (auto& zone : mZones) {
1186         candidates.erase(zone->getVT());
1187     }
1188     if (candidates.empty()) {
1189         const std::string msg = "No free VT for zone";
1190         LOGE(msg);
1191         throw ZoneOperationException(msg);
1192     }
1193     // return the smallest
1194     return *candidates.begin();
1195 }
1196
1197 void ZonesManager::createZone(const std::string& id,
1198                               const std::string& templateName)
1199 {
1200     if (id.empty() || !isalnum(id)) {
1201         const std::string msg = "Failed to add zone - invalid name.";
1202         LOGE(msg);
1203         throw InvalidZoneIdException(msg);
1204     }
1205
1206     if (find(prohibitedZonesNames.begin(), prohibitedZonesNames.end(), id) != prohibitedZonesNames.end()) {
1207         const std::string msg = "Cannot create " + id + " zone - name is not allowed!";
1208         LOGE(msg);
1209         throw InvalidZoneIdException(msg);
1210     }
1211
1212     LOGI("Creating zone " << id);
1213
1214     Lock lock(mMutex);
1215
1216     // TODO: This solution is temporary. It utilizes direct access to config files when creating new
1217     // zones. Update this handler when config database will appear.
1218     namespace fs = boost::filesystem;
1219
1220     // check if zone does not exist
1221     if (findZone(id) != mZones.end()) {
1222         const std::string msg = "Cannot create " + id + " zone - already exists!";
1223         LOGE(msg);
1224         throw InvalidZoneIdException(msg);
1225     }
1226
1227     if (fs::exists(fs::path(mConfig.zonesPath) / id)) {
1228         const std::string msg = "Cannot create " + id + " zone - file system already exists!";
1229         LOGE(msg);
1230         throw InvalidZoneIdException(msg);
1231     }
1232
1233     const std::string zonePathStr = utils::createFilePath(mConfig.zonesPath, id, "/");
1234
1235     // copy zone image if config contains path to image
1236     LOGT("Image path: " << mConfig.zoneImagePath);
1237     if (!mConfig.zoneImagePath.empty()) {
1238         auto copyImageContentsWrapper = std::bind(&utils::copyImageContents,
1239                                                   mConfig.zoneImagePath,
1240                                                   zonePathStr);
1241
1242         if (!utils::launchAsRoot(copyImageContentsWrapper)) {
1243             const std::string msg = "Failed to copy zone image.";
1244             LOGE(msg);
1245             throw ZoneOperationException(msg);
1246         }
1247     }
1248
1249     auto removeAllWrapper = [](const std::string & path) -> bool {
1250         try {
1251             LOGD("Removing copied data");
1252             fs::remove_all(fs::path(path));
1253         } catch (const std::exception& e) {
1254             LOGW("Failed to remove data: " << boost::diagnostic_information(e));
1255         }
1256         return true;
1257     };
1258
1259     std::string zoneTemplatePath = utils::createFilePath(mConfig.zoneTemplateDir,
1260                                                          templateName + ".conf");
1261
1262     try {
1263         LOGI("Generating config from " << zoneTemplatePath);
1264         generateNewConfig(id, zoneTemplatePath);
1265     } catch (std::runtime_error& e) {
1266         LOGE("Generate config failed: " << e.what());
1267         utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr));
1268         throw;
1269     }
1270
1271     LOGT("Creating new zone");
1272     try {
1273         insertZone(id, zoneTemplatePath);
1274     } catch (std::runtime_error& e) {
1275         LOGE("Creating new zone failed: " << e.what());
1276         utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr));
1277         throw;
1278     }
1279
1280     mDynamicConfig.zoneIds.push_back(id);
1281     saveDynamicConfig();
1282     updateDefaultId();
1283 }
1284
1285 void ZonesManager::handleCreateZoneCall(const api::CreateZoneIn& data,
1286                                         api::MethodResultBuilder::Pointer result)
1287 {
1288     auto creator = [&, this] {
1289         try {
1290             createZone(data.first, data.second);
1291             result->setVoid();
1292         } catch (const InvalidZoneIdException& e) {
1293             result->setError(api::ERROR_INVALID_ID, e.what());
1294         } catch (const std::exception& e) {
1295             result->setError(api::ERROR_INTERNAL, e.what());
1296         }
1297     };
1298
1299     tryAddTask(creator, result, true);
1300 }
1301
1302 void ZonesManager::handleDestroyZoneCall(const api::ZoneId& zoneId,
1303                                          api::MethodResultBuilder::Pointer result)
1304 {
1305     auto destroyer = [=] {
1306         try {
1307             LOGI("Destroying zone " << zoneId.value);
1308             destroyZone(zoneId.value);
1309         } catch (const InvalidZoneIdException&) {
1310             LOGE("Failed to destroy zone - no such zone id: " << zoneId.value);
1311             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1312         } catch (const std::runtime_error& e) {
1313             LOGE("Error during zone destruction: " << e.what());
1314             result->setError(api::ERROR_INTERNAL, "Failed to destroy zone");
1315             return;
1316         }
1317         result->setVoid();
1318     };
1319
1320     tryAddTask(destroyer, result, false);
1321 }
1322
1323 void ZonesManager::handleShutdownZoneCall(const api::ZoneId& zoneId,
1324                                           api::MethodResultBuilder::Pointer result)
1325 {
1326     auto shutdown = [=] {
1327         LOGI("ShutdownZone call; Id=" << zoneId.value);
1328
1329         try {
1330             LOGT("Shutdown zone " << zoneId.value);
1331
1332             Lock lock(mMutex);
1333             auto iter = findZone(zoneId.value);
1334             if (iter == mZones.end()) {
1335                 LOGE("Failed to shutdown zone - no such zone id: " << zoneId.value);
1336                 result->setError(api::ERROR_INVALID_ID, "No such zone id");
1337                 return;
1338             }
1339             get(iter).stop(true);
1340             refocus();
1341             result->setVoid();
1342         } catch (ZoneOperationException& e) {
1343             LOGE("Error during zone shutdown: " << e.what());
1344             result->setError(api::ERROR_INTERNAL, "Failed to shutdown zone");
1345             return;
1346         }
1347     };
1348
1349     tryAddTask(shutdown, result, false);
1350 }
1351
1352 void ZonesManager::handleStartZoneCall(const api::ZoneId& zoneId,
1353                                        api::MethodResultBuilder::Pointer result)
1354 {
1355     auto startAsync = [=] {
1356         LOGI("StartZone call; Id=" << zoneId.value);
1357
1358         try {
1359             LOGT("Start zone " << zoneId.value);
1360
1361             Lock lock(mMutex);
1362             auto iter = findZone(zoneId.value);
1363             if (iter == mZones.end()) {
1364                 LOGE("Failed to start zone - no such zone id: " << zoneId.value);
1365                 result->setError(api::ERROR_INVALID_ID, "No such zone id");
1366                 return;
1367             }
1368             get(iter).start();
1369             focusInternal(iter);
1370             result->setVoid();
1371         } catch (const std::exception& e) {
1372             LOGE(zoneId.value << ": failed to start: " << e.what());
1373             result->setError(api::ERROR_INTERNAL, "Failed to start zone");
1374         }
1375     };
1376     tryAddTask(startAsync, result, false);
1377 }
1378
1379 void ZonesManager::handleLockZoneCall(const api::ZoneId& zoneId,
1380                                       api::MethodResultBuilder::Pointer result)
1381 {
1382     auto handler = [&, this] {
1383         LOGI("LockZone call; Id=" << zoneId.value );
1384
1385         Lock lock(mMutex);
1386
1387         auto iter = findZone(zoneId.value);
1388         if (iter == mZones.end()) {
1389             LOGE("Failed to lock zone - no such zone id: " << zoneId.value);
1390             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1391             return;
1392         }
1393
1394         Zone& zone = get(iter);
1395         if (!zone.isRunning()) {
1396             LOGE("Zone id=" << zoneId.value << " is not running.");
1397             result->setError(api::ERROR_INVALID_STATE, "Zone is not running");
1398             return;
1399         }
1400
1401         LOGT("Lock zone");
1402         try {
1403             zone.goBackground();// make sure it will be in background after unlock
1404             zone.suspend();
1405             refocus();
1406         } catch (ZoneOperationException& e) {
1407             LOGE(e.what());
1408             result->setError(api::ERROR_INTERNAL, e.what());
1409             return;
1410         }
1411
1412         result->setVoid();
1413     };
1414
1415     tryAddTask(handler, result, true);
1416 }
1417
1418 void ZonesManager::handleUnlockZoneCall(const api::ZoneId& zoneId,
1419                                         api::MethodResultBuilder::Pointer result)
1420 {
1421     auto handler = [&, this] {
1422         LOGI("UnlockZone call; Id=" << zoneId.value );
1423
1424         Lock lock(mMutex);
1425
1426         auto iter = findZone(zoneId.value);
1427         if (iter == mZones.end()) {
1428             LOGE("Failed to unlock zone - no such zone id: " << zoneId.value);
1429             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1430             return;
1431         }
1432
1433         Zone& zone = get(iter);
1434         if (!zone.isPaused()) {
1435             LOGE("Zone id=" << zoneId.value << " is not paused.");
1436             result->setError(api::ERROR_INVALID_STATE, "Zone is not paused");
1437             return;
1438         }
1439
1440         LOGT("Unlock zone");
1441         try {
1442             zone.resume();
1443         } catch (ZoneOperationException& e) {
1444             LOGE(e.what());
1445             result->setError(api::ERROR_INTERNAL, e.what());
1446             return;
1447         }
1448
1449         result->setVoid();
1450     };
1451
1452     tryAddTask(handler, result, true);
1453 }
1454
1455 void ZonesManager::handleGrantDeviceCall(const api::GrantDeviceIn& data,
1456                                          api::MethodResultBuilder::Pointer result)
1457 {
1458     auto handler = [&, this] {
1459         LOGI("GrantDevice call; id=" << data.id << "; dev=" << data.device);
1460
1461         Lock lock(mMutex);
1462
1463         auto iter = findZone(data.id);
1464         if (iter == mZones.end()) {
1465             LOGE("Failed to grant device - no such zone id: " << data.id);
1466             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1467             return;
1468         }
1469
1470         Zone& zone = get(iter);
1471         if (!zone.isRunning() && !zone.isPaused()) {
1472             LOGE("Zone id=" << data.id << " is not running");
1473             result->setError(api::ERROR_INVALID_STATE, "Zone is not running");
1474             return;
1475         }
1476
1477         std::string devicePath = "/dev/" + data.device;
1478
1479         if (!lxc::isDevice(devicePath)) {
1480             LOGE("Failed to grant device - cannot acces device: " << data.device);
1481             result->setError(api::ERROR_FORBIDDEN, "Cannot access device");
1482             return;
1483         }
1484
1485         // assume device node is created inside zone
1486         if (!lxc::setDeviceAccess(data.id, devicePath, true, data.flags)) {
1487             LOGE("Failed to grant device: " << data.device << " for zone: " << data.id);
1488             result->setError(api::ERROR_INTERNAL, "Cannot grant device");
1489             return;
1490         }
1491
1492         result->setVoid();
1493     };
1494
1495     tryAddTask(handler, result, true);
1496 }
1497
1498 void ZonesManager::handleRevokeDeviceCall(const api::RevokeDeviceIn& data,
1499                                           api::MethodResultBuilder::Pointer result)
1500 {
1501     auto handler = [&, this] {
1502         LOGI("RevokeDevice call; id=" << data.first << "; dev=" << data.second);
1503
1504         Lock lock(mMutex);
1505
1506         auto iter = findZone(data.first);
1507         if (iter == mZones.end()) {
1508             LOGE("Failed to revoke device - no such zone id: " << data.first);
1509             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1510             return;
1511         }
1512
1513         Zone& zone = get(iter);
1514         if (!zone.isRunning() && !zone.isPaused()) {
1515             LOGE("Zone id=" << data.first << " is not running");
1516             result->setError(api::ERROR_INVALID_STATE, "Zone is not running");
1517             return;
1518         }
1519         std::string devicePath = "/dev/" + data.second;
1520
1521         if (!lxc::isDevice(devicePath)) {
1522             LOGE("Failed to revoke device - cannot acces device: " << data.second);
1523             result->setError(api::ERROR_FORBIDDEN, "Cannot access device");
1524             return;
1525         }
1526
1527         if (!lxc::setDeviceAccess(data.first, devicePath, false, 0)) {
1528             LOGE("Failed to revoke device: " << data.second << " for zone: " << data.first);
1529             result->setError(api::ERROR_INTERNAL, "Cannot revoke device");
1530             return;
1531         }
1532
1533         result->setVoid();
1534     };
1535
1536     tryAddTask(handler, result, true);
1537 }
1538
1539 void ZonesManager::handleCleanUpZonesRootCall(api::MethodResultBuilder::Pointer result)
1540 {
1541     auto handler = [&, this] {
1542         LOGI("CleanUpZonesRoot call");
1543         try {
1544             std::vector<std::string> zonesIds;
1545             Lock lock(mMutex);
1546             for (const auto& zone : mZones) {
1547                 zonesIds.push_back(zone->getId());
1548             }
1549             cleanUpUnknownsFromRoot(mConfig.zonesPath, zonesIds, false);
1550         } catch (const std::exception& e) {
1551             result->setError(api::ERROR_INTERNAL, e.what());
1552         }
1553         result->setVoid();
1554     };
1555
1556     tryAddTask(handler, result, true);
1557 }
1558
1559 } // namespace vasum