c45aa22ea4db84cdd7d7673ace83f4c503bbf0e2
[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             if (mConfig.hostVT > 0) {
396                 LOGI("Focus to: host");
397                 utils::activateVT(mConfig.hostVT);
398             }
399             mActiveZoneId.clear();
400         }
401         return;
402     }
403
404     Zone& zoneToFocus = get(iter);
405     const std::string& idToFocus = zoneToFocus.getId();
406
407     if (idToFocus == mActiveZoneId) {
408         return;
409     }
410
411     if (!zoneToFocus.isRunning()) {
412         LOGE("Can't focus not running zone " << idToFocus);
413         assert(false);
414         return;
415     }
416
417     LOGI("Focus to: " << idToFocus);
418
419     if (!zoneToFocus.activateVT()) {
420         LOGE("Failed to activate zones VT");
421         return;
422     }
423
424     for (auto& zone : mZones) {
425         if (zone->isRunning()) {
426             std::string id = zone->getId();
427             if (id == idToFocus) {
428                 LOGD(id << ": being sent to foreground");
429                 zone->goForeground();
430             } else {
431                 LOGD(id << ": being sent to background");
432                 zone->goBackground();
433             }
434         }
435     }
436     mActiveZoneId = idToFocus;
437 }
438
439 void ZonesManager::refocus()
440 {
441     // assume mutex is locked
442
443     // check if refocus is required
444     auto oldIter = findZone(mActiveZoneId);
445     if (oldIter != mZones.end() && get(oldIter).isRunning()) {
446         return;
447     }
448
449     // try to refocus to defaultId
450     auto iter = findZone(mDynamicConfig.defaultId);
451     if (iter == mZones.end() || !get(iter).isRunning()) {
452         // focus to any running or to host if not found
453         iter = std::find_if(mZones.begin(), mZones.end(), zoneIsRunning);
454     }
455     focusInternal(iter);
456 }
457
458 void ZonesManager::restoreAll()
459 {
460     LOGI("Restoring all zones");
461
462     Lock lock(mMutex);
463
464     for (auto& zone : mZones) {
465         zone->restore();
466         // FIXME wait until zone is started and stable
467         // there is problem (with lxc-start) when starting zones too fast
468         // here or in zone.cpp after start
469         std::this_thread::sleep_for(std::chrono::milliseconds(500));
470     }
471
472     refocus();
473 }
474
475 void ZonesManager::shutdownAll()
476 {
477     LOGI("Stopping all zones");
478
479     Lock lock(mMutex);
480
481     for (auto& zone : mZones) {
482         zone->stop(false);
483     }
484
485     refocus();
486 }
487
488 bool ZonesManager::isPaused(const std::string& zoneId)
489 {
490     Lock lock(mMutex);
491     return getZone(zoneId).isPaused();
492 }
493
494 bool ZonesManager::isRunning(const std::string& zoneId)
495 {
496     Lock lock(mMutex);
497     return getZone(zoneId).isRunning();
498 }
499
500 bool ZonesManager::isStopped(const std::string& zoneId)
501 {
502     Lock lock(mMutex);
503     return getZone(zoneId).isStopped();
504 }
505
506 std::string ZonesManager::getRunningForegroundZoneId()
507 {
508     Lock lock(mMutex);
509     auto iter = getRunningForegroundZoneIterator();
510     return iter == mZones.end() ? std::string() : get(iter).getId();
511 }
512
513 std::string ZonesManager::getNextToForegroundZoneId()
514 {
515     Lock lock(mMutex);
516     auto iter = getNextToForegroundZoneIterator();
517     return iter == mZones.end() ? std::string() : get(iter).getId();
518 }
519
520 ZonesManager::Zones::iterator ZonesManager::getRunningForegroundZoneIterator()
521 {
522     // assume mutex is locked
523     if (mActiveZoneId.empty()) {
524         return mZones.end();
525     }
526     auto iter = findZone(mActiveZoneId);
527     if (!get(iter).isRunning()) {
528         LOGW("Active zone " << mActiveZoneId << " is not running any more!");
529         return mZones.end();
530     }
531     return iter;
532 }
533
534 ZonesManager::Zones::iterator ZonesManager::getNextToForegroundZoneIterator()
535 {
536     // assume mutex is locked
537     auto current = findZone(mActiveZoneId);
538     if (current == mZones.end()) {
539         // find any running
540         return std::find_if(mZones.begin(), mZones.end(), zoneIsRunning);
541     } else {
542         // find next running
543         return circularFindNext(mZones.begin(), mZones.end(), current, zoneIsRunning);
544     }
545 }
546
547 void ZonesManager::switchingSequenceMonitorNotify()
548 {
549     LOGI("switchingSequenceMonitorNotify() called");
550
551     Lock lock(mMutex);
552
553     auto next = getNextToForegroundZoneIterator();
554
555     if (next != mZones.end()) {
556         focusInternal(next);
557     }
558 }
559
560
561 void ZonesManager::setZonesDetachOnExit()
562 {
563     Lock lock(mMutex);
564
565     mDetachOnExit = true;
566
567     for (auto& zone : mZones) {
568         zone->setDetachOnExit();
569     }
570 }
571
572 void ZonesManager::disconnectedCallback(const std::string& id)
573 {
574     LOGD("Client Disconnected: " << id);
575
576     {
577         Lock lock(mExclusiveIDMutex);
578
579         if (mExclusiveIDLock == id) {
580             mExclusiveIDLock = INVALID_CONNECTION_ID;
581         }
582     }
583 }
584
585 void ZonesManager::handleSwitchToDefaultCall(const std::string& /*caller*/,
586                                              api::MethodResultBuilder::Pointer result)
587 {
588     auto handler = [&, this] {
589         // get config of currently set zone and switch if switchToDefaultAfterTimeout is true
590         Lock lock(mMutex);
591
592         auto activeIter = findZone(mActiveZoneId);
593         auto defaultIter = findZone(mDynamicConfig.defaultId);
594
595         if (activeIter != mZones.end() &&
596             defaultIter != mZones.end() &&
597             get(activeIter).isSwitchToDefaultAfterTimeoutAllowed() &&
598             get(defaultIter).isRunning()) {
599
600             LOGI("Switching to default zone " << mDynamicConfig.defaultId);
601             focusInternal(defaultIter);
602         }
603         result->setVoid();
604     };
605
606     tryAddTask(handler, result, true);
607 }
608
609 void ZonesManager::handleCreateFileCall(const api::CreateFileIn& request,
610                                         api::MethodResultBuilder::Pointer result)
611 {
612     auto handler = [&, this] {
613         LOGI("CreateFile call");
614
615         Lock lock(mMutex);
616
617         auto srcIter = findZone(request.id);
618         if (srcIter == mZones.end()) {
619             LOGE("Zone '" << request.id << "' not found");
620             result->setError(api::ERROR_INVALID_ID, "Requested Zone was not found.");
621             return;
622         }
623         Zone& srcZone = get(srcIter);
624
625         auto retValue = std::make_shared<api::CreateFileOut>();
626         try {
627             retValue->fd = srcZone.createFile(request.path, request.flags, request.mode);
628         } catch(ZoneOperationException& e) {
629             result->setError(api::ERROR_CREATE_FILE_FAILED, "Unable to create file");
630             return;
631         }
632
633         result->set(retValue);
634     };
635
636     tryAddTask(handler, result, true);
637 }
638
639 #ifdef DBUS_CONNECTION
640 void ZonesManager::handleProxyCall(const std::string& caller,
641                                    const std::string& target,
642                                    const std::string& targetBusName,
643                                    const std::string& targetObjectPath,
644                                    const std::string& targetInterface,
645                                    const std::string& targetMethod,
646                                    GVariant* parameters,
647                                    dbus::MethodResultBuilder::Pointer result)
648 {
649     auto handler = [&, this] {
650         if (!mProxyCallPolicy->isProxyCallAllowed(caller,
651                                                   target,
652                                                   targetBusName,
653                                                   targetObjectPath,
654                                                   targetInterface,
655                                                   targetMethod)) {
656             LOGW("Forbidden proxy call; " << caller << " -> " << target << "; " << targetBusName
657                  << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod);
658             result->setError(api::ERROR_FORBIDDEN, "Proxy call forbidden");
659             return;
660         }
661
662         LOGI("Proxy call; " << caller << " -> " << target << "; " << targetBusName
663              << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod);
664
665         auto asyncResultCallback = [result](dbus::AsyncMethodCallResult & asyncMethodCallResult) {
666             try {
667                 GVariant* targetResult = asyncMethodCallResult.get();
668                 result->set(g_variant_new("(v)", targetResult));
669             } catch (dbus::DbusException& e) {
670                 result->setError(api::ERROR_FORWARDED, e.what());
671             }
672         };
673
674         if (target != HOST_ID) {
675             result->setError(api::ERROR_INVALID_ID, "Unknown proxy call target");
676             return;
677         }
678
679         mHostDbusConnection.proxyCallAsync(targetBusName,
680                                            targetObjectPath,
681                                            targetInterface,
682                                            targetMethod,
683                                            parameters,
684                                            asyncResultCallback);
685     };
686
687     // This call cannot be locked by lock/unlock queue
688     mWorker->addTaskAndWait(handler);
689 }
690 #endif //DBUS_CONNECTION
691
692 void ZonesManager::handleLockQueueCall(api::MethodResultBuilder::Pointer result)
693 {
694     Lock lock(mExclusiveIDMutex);
695     std::string id = result->getID();
696
697     LOGI("Lock Queue: " << id);
698
699     if (mExclusiveIDLock == id) {
700         result->setError(api::ERROR_QUEUE, "Queue already locked");
701         return;
702     }
703
704     if (mExclusiveIDLock != INVALID_CONNECTION_ID) {
705         result->setError(api::ERROR_QUEUE, "Queue locked by another connection");
706         return;
707     }
708
709     mExclusiveIDLock = id;
710     result->setVoid();
711 }
712
713 void ZonesManager::handleUnlockQueueCall(api::MethodResultBuilder::Pointer result)
714 {
715     Lock lock(mExclusiveIDMutex);
716     std::string id = result->getID();
717
718     LOGI("Unlock Queue: " << id);
719
720     if (mExclusiveIDLock == INVALID_CONNECTION_ID) {
721         result->setError(api::ERROR_QUEUE, "Queue not locked");
722         return;
723     }
724
725     if (mExclusiveIDLock != id) {
726         result->setError(api::ERROR_QUEUE, "Queue locked by another connection");
727         return;
728     }
729
730     mExclusiveIDLock = INVALID_CONNECTION_ID;
731     result->setVoid();
732 }
733
734 void ZonesManager::handleGetZoneIdsCall(api::MethodResultBuilder::Pointer result)
735 {
736     auto handler = [&, this] {
737         LOGI("GetZoneIds call");
738
739         Lock lock(mMutex);
740
741         auto zoneIds = std::make_shared<api::ZoneIds>();
742         for (const auto& zone : mZones) {
743             zoneIds->values.push_back(zone->getId());
744         }
745
746         result->set(zoneIds);
747     };
748
749     // This call cannot be locked by lock/unlock queue
750     mWorker->addTaskAndWait(handler);
751 }
752
753 void ZonesManager::handleGetActiveZoneIdCall(api::MethodResultBuilder::Pointer result)
754 {
755     auto handler = [&, this] {
756         LOGI("GetActiveZoneId call");
757
758         auto zoneId = std::make_shared<api::ZoneId>();
759         zoneId->value = getRunningForegroundZoneId();
760         result->set(zoneId);
761     };
762
763     // This call cannot be locked by lock/unlock queue
764     mWorker->addTaskAndWait(handler);
765 }
766
767 void ZonesManager::handleGetZoneInfoCall(const api::ZoneId& zoneId,
768                                          api::MethodResultBuilder::Pointer result)
769 {
770     auto handler = [&, this] {
771         LOGI("GetZoneInfo call");
772
773         Lock lock(mMutex);
774
775         auto iter = findZone(zoneId.value);
776         if (iter == mZones.end()) {
777             LOGE("No zone with id=" << zoneId.value);
778             result->setError(api::ERROR_INVALID_ID, "No such zone id");
779             return;
780         }
781
782         Zone& zone = get(iter);
783         auto zoneInfo = std::make_shared<api::ZoneInfoOut>();
784
785         if (zone.isRunning()) {
786             zoneInfo->state = "RUNNING";
787         } else if (zone.isStopped()) {
788             zoneInfo->state = "STOPPED";
789         } else if (zone.isPaused()) {
790             zoneInfo->state = "FROZEN";
791         } else {
792             LOGE("Unrecognized state of zone id=" << zoneId.value);
793             result->setError(api::ERROR_INTERNAL, "Unrecognized state of zone");
794             return;
795         }
796
797         zoneInfo->id = zone.getId();
798         zoneInfo->vt = zone.getVT();
799         zoneInfo->rootPath = zone.getRootPath();
800         result->set(zoneInfo);
801     };
802
803     // This call cannot be locked by lock/unlock queue
804     mWorker->addTaskAndWait(handler);
805 }
806
807 void ZonesManager::handleSetNetdevAttrsCall(const api::SetNetDevAttrsIn& data,
808                                             api::MethodResultBuilder::Pointer result)
809 {
810     auto handler = [&, this] {
811         LOGI("SetNetdevAttrs call");
812
813         try {
814             Lock lock(mMutex);
815
816             // TODO: Use vector<StringPair> instead of tuples
817             std::vector<std::tuple<std::string, std::string>> attrsAsTuples;
818             for(const auto& entry: data.attrs){
819                 attrsAsTuples.push_back(std::make_tuple(entry.first, entry.second));
820             }
821
822             getZone(data.id).setNetdevAttrs(data.netDev, attrsAsTuples);
823             result->setVoid();
824         } catch (const InvalidZoneIdException&) {
825             LOGE("No zone with id=" << data.id);
826             result->setError(api::ERROR_INVALID_ID, "No such zone id");
827         } catch (const std::runtime_error& ex) {
828             LOGE("Can't set attributes: " << ex.what());
829             result->setError(api::ERROR_INTERNAL, ex.what());
830         }
831     };
832
833     tryAddTask(handler, result, true);
834 }
835
836 void ZonesManager::handleGetNetdevAttrsCall(const api::GetNetDevAttrsIn& data,
837                                             api::MethodResultBuilder::Pointer result)
838 {
839     auto handler = [&, this] {
840         LOGI("GetNetdevAttrs call");
841
842         try {
843             Lock lock(mMutex);
844             auto netDevAttrs = std::make_shared<api::GetNetDevAttrs>();
845             const auto attrs = getZone(data.first).getNetdevAttrs(data.second);
846
847             for (size_t i = 0; i < attrs.size(); ++i) {
848                 netDevAttrs->values.push_back({std::get<0>(attrs[i]), std::get<1>(attrs[i])});
849             }
850             result->set(netDevAttrs);
851         } catch (const InvalidZoneIdException&) {
852             LOGE("No zone with id=" << data.first);
853             result->setError(api::ERROR_INVALID_ID, "No such zone id");
854         } catch (const std::runtime_error& ex) {
855             LOGE("Can't set attributes: " << ex.what());
856             result->setError(api::ERROR_INTERNAL, ex.what());
857         }
858     };
859
860     tryAddTask(handler, result, true);
861 }
862
863 void ZonesManager::handleGetNetdevListCall(const api::ZoneId& zoneId,
864                                            api::MethodResultBuilder::Pointer result)
865 {
866     auto handler = [&, this] {
867         LOGI("GetNetdevList call");
868
869         try {
870             Lock lock(mMutex);
871             auto netDevList = std::make_shared<api::NetDevList>();
872             netDevList->values = getZone(zoneId.value).getNetdevList();
873             result->set(netDevList);
874         } catch (const InvalidZoneIdException&) {
875             LOGE("No zone with id=" << zoneId.value);
876             result->setError(api::ERROR_INVALID_ID, "No such zone id");
877         } catch (const std::runtime_error& ex) {
878             LOGE("Can't set attributes: " << ex.what());
879             result->setError(api::ERROR_INTERNAL, ex.what());
880         }
881     };
882
883     tryAddTask(handler, result, true);
884 }
885
886 void ZonesManager::handleCreateNetdevVethCall(const api::CreateNetDevVethIn& data,
887                                               api::MethodResultBuilder::Pointer result)
888 {
889     auto handler = [&, this] {
890         LOGI("CreateNetdevVeth call");
891
892         try {
893             Lock lock(mMutex);
894
895             getZone(data.id).createNetdevVeth(data.zoneDev, data.hostDev);
896             result->setVoid();
897         } catch (const InvalidZoneIdException&) {
898             LOGE("No zone with id=" << data.id);
899             result->setError(api::ERROR_INVALID_ID, "No such zone id");
900         } catch (const std::runtime_error& ex) {
901             LOGE("Can't create veth: " << ex.what());
902             result->setError(api::ERROR_INTERNAL, ex.what());
903         }
904     };
905
906     tryAddTask(handler, result, true);
907 }
908
909 void ZonesManager::handleCreateNetdevMacvlanCall(const api::CreateNetDevMacvlanIn& data,
910                                                  api::MethodResultBuilder::Pointer result)
911 {
912     auto handler = [&, this] {
913         LOGI("CreateNetdevMacvlan call");
914
915         try {
916             Lock lock(mMutex);
917             getZone(data.id).createNetdevMacvlan(data.zoneDev, data.hostDev, data.mode);
918             result->setVoid();
919         } catch (const InvalidZoneIdException&) {
920             LOGE("No zone with id=" << data.id);
921             result->setError(api::ERROR_INVALID_ID, "No such zone id");
922         } catch (const std::runtime_error& ex) {
923             LOGE("Can't create macvlan: " << ex.what());
924             result->setError(api::ERROR_INTERNAL, ex.what());
925         }
926     };
927
928     tryAddTask(handler, result, true);
929 }
930
931 void ZonesManager::handleCreateNetdevPhysCall(const api::CreateNetDevPhysIn& data,
932                                               api::MethodResultBuilder::Pointer result)
933 {
934     auto handler = [&, this] {
935         LOGI("CreateNetdevPhys call");
936
937         try {
938             Lock lock(mMutex);
939
940             getZone(data.first).moveNetdev(data.second);
941             result->setVoid();
942         } catch (const InvalidZoneIdException&) {
943             LOGE("No zone with id=" << data.first);
944             result->setError(api::ERROR_INVALID_ID, "No such zone id");
945         } catch (const std::runtime_error& ex) {
946             LOGE("Can't create netdev: " << ex.what());
947             result->setError(api::ERROR_INTERNAL, ex.what());
948         }
949     };
950
951     tryAddTask(handler, result, true);
952 }
953
954 void ZonesManager::handleDestroyNetdevCall(const api::DestroyNetDevIn& data,
955                                            api::MethodResultBuilder::Pointer result)
956 {
957     auto handler = [&, this] {
958         LOGI("DestroyNetdev call");
959
960         try {
961             Lock lock(mMutex);
962
963             getZone(data.first).destroyNetdev(data.second);
964             result->setVoid();
965         } catch (const InvalidZoneIdException&) {
966             LOGE("No zone with id=" << data.first);
967             result->setError(api::ERROR_INVALID_ID, "No such zone id");
968         } catch (const std::runtime_error& ex) {
969             LOGE("Can't create netdev: " << ex.what());
970             result->setError(api::ERROR_INTERNAL, ex.what());
971         }
972     };
973
974     tryAddTask(handler, result, true);
975 }
976
977 void ZonesManager::handleDeleteNetdevIpAddressCall(const api::DeleteNetdevIpAddressIn& data,
978                                                    api::MethodResultBuilder::Pointer result)
979 {
980     auto handler = [&, this] {
981         LOGI("DelNetdevIpAddress call");
982
983         try {
984             Lock lock(mMutex);
985             getZone(data.zone).deleteNetdevIpAddress(data.netdev, data.ip);
986             result->setVoid();
987         } catch (const InvalidZoneIdException&) {
988             LOGE("No zone with id=" << data.zone);
989             result->setError(api::ERROR_INVALID_ID, "No such zone id");
990         } catch (const std::runtime_error& ex) {
991             LOGE("Can't delete address: " << ex.what());
992             result->setError(api::ERROR_INTERNAL, ex.what());
993         }
994     };
995
996     tryAddTask(handler, result, true);
997 }
998
999 void ZonesManager::handleDeclareFileCall(const api::DeclareFileIn& data,
1000                                          api::MethodResultBuilder::Pointer result)
1001 {
1002     auto handler = [&, this] {
1003         LOGI("DeclareFile call");
1004
1005         try {
1006             Lock lock(mMutex);
1007             auto declaration = std::make_shared<api::Declaration>();
1008             declaration->value = getZone(data.zone).declareFile(data.type, data.path, data.flags, data.mode);
1009             result->set(declaration);
1010         } catch (const InvalidZoneIdException&) {
1011             LOGE("No zone with id=" << data.zone);
1012             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1013         } catch (const config::ConfigException& ex) {
1014             LOGE("Can't declare file: " << ex.what());
1015             result->setError(api::ERROR_INTERNAL, "Internal error");
1016         }
1017     };
1018
1019     tryAddTask(handler, result, true);
1020 }
1021
1022 void ZonesManager::handleDeclareMountCall(const api::DeclareMountIn& data,
1023                                           api::MethodResultBuilder::Pointer result)
1024 {
1025     auto handler = [&, this] {
1026         LOGI("DeclareMount call");
1027
1028         try {
1029             Lock lock(mMutex);
1030             auto declaration = std::make_shared<api::Declaration>();
1031             declaration->value = getZone(data.zone).declareMount(data.source, data.target, data.type, data.flags, data.data);
1032             result->set(declaration);
1033         } catch (const InvalidZoneIdException&) {
1034             LOGE("No zone with id=" << data.zone);
1035             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1036         } catch (const config::ConfigException& ex) {
1037             LOGE("Can't declare mount: " << ex.what());
1038             result->setError(api::ERROR_INTERNAL, "Internal error");
1039         }
1040     };
1041
1042     tryAddTask(handler, result, true);
1043 }
1044
1045 void ZonesManager::handleDeclareLinkCall(const api::DeclareLinkIn& data,
1046                                          api::MethodResultBuilder::Pointer result)
1047 {
1048     auto handler = [&, this] {
1049         LOGI("DeclareLink call");
1050
1051         try {
1052             Lock lock(mMutex);
1053             auto declaration = std::make_shared<api::Declaration>();
1054             declaration->value = getZone(data.zone).declareLink(data.source, data.target);
1055             result->set(declaration);
1056         } catch (const InvalidZoneIdException&) {
1057             LOGE("No zone with id=" << data.zone);
1058             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1059         } catch (const config::ConfigException& ex) {
1060             LOGE("Can't declare link: " << ex.what());
1061             result->setError(api::ERROR_INTERNAL, "Internal error");
1062         }
1063     };
1064
1065     tryAddTask(handler, result, true);
1066 }
1067
1068 void ZonesManager::handleGetDeclarationsCall(const api::ZoneId& zoneId,
1069                                              api::MethodResultBuilder::Pointer result)
1070 {
1071     auto handler = [&, this] {
1072         LOGI("GetDeclarations call Id=" << zoneId.value);
1073
1074         try {
1075             Lock lock(mMutex);
1076             auto declarations = std::make_shared<api::Declarations>();
1077             declarations->values = getZone(zoneId.value).getDeclarations();
1078             result->set(declarations);
1079         } catch (const InvalidZoneIdException&) {
1080             LOGE("No zone with id=" << zoneId.value);
1081             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1082         } catch (const std::runtime_error& ex) {
1083             LOGE(ex.what());
1084             result->setError(api::ERROR_INTERNAL, ex.what());
1085         }
1086     };
1087
1088     tryAddTask(handler, result, true);
1089 }
1090
1091 void ZonesManager::handleRemoveDeclarationCall(const api::RemoveDeclarationIn& data,
1092                                                api::MethodResultBuilder::Pointer result)
1093 {
1094     auto handler = [&, this] {
1095         LOGI("RemoveDeclaration call Id=" << data.first);
1096
1097         try {
1098             Lock lock(mMutex);
1099             getZone(data.first).removeDeclaration(data.second);
1100             result->setVoid();
1101         } catch (const InvalidZoneIdException&) {
1102             LOGE("No zone with id=" << data.first);
1103             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1104         } catch (const std::runtime_error& ex) {
1105             LOGE(ex.what());
1106             result->setError(api::ERROR_INTERNAL, ex.what());
1107         }
1108     };
1109
1110     tryAddTask(handler, result, true);
1111 }
1112
1113 void ZonesManager::handleSetActiveZoneCall(const api::ZoneId& zoneId,
1114                                            api::MethodResultBuilder::Pointer result)
1115 {
1116     auto handler = [&, this] {
1117         LOGI("SetActiveZone call; Id=" << zoneId.value );
1118
1119         Lock lock(mMutex);
1120
1121         auto iter = findZone(zoneId.value);
1122         if (iter == mZones.end()) {
1123             LOGE("No zone with id=" << zoneId.value);
1124             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1125             return;
1126         }
1127
1128         if (!get(iter).isRunning()) {
1129             LOGE("Could not activate stopped or paused zone");
1130             result->setError(api::ERROR_ZONE_NOT_RUNNING,
1131                              "Could not activate stopped or paused zone");
1132             return;
1133         }
1134
1135         focusInternal(iter);
1136         result->setVoid();
1137     };
1138
1139     tryAddTask(handler, result, true);
1140 }
1141
1142
1143 void ZonesManager::generateNewConfig(const std::string& id,
1144                                      const std::string& templatePath)
1145 {
1146     const std::string dbPrefix = getZoneDbPrefix(id);
1147     ZoneDynamicConfig dynamicConfig;
1148     config::loadFromKVStoreWithJsonFile(mConfig.dbPath, templatePath, dynamicConfig, dbPrefix);
1149
1150     // update mount point path
1151     dynamicConfig.runMountPoint = boost::regex_replace(dynamicConfig.runMountPoint,
1152                                                        ZONE_NAME_REGEX,
1153                                                        id);
1154
1155     if (dynamicConfig.vt >= 0) {
1156         // generate first free VT number
1157         const int freeVT = getVTForNewZone();
1158         LOGD("VT number: " << freeVT);
1159         dynamicConfig.vt = freeVT;
1160
1161         if (!dynamicConfig.ipv4Gateway.empty() && !dynamicConfig.ipv4.empty()) {
1162             // generate third IP octet for network config
1163             std::string thirdOctetStr = std::to_string(ZONE_IP_BASE_THIRD_OCTET + freeVT);
1164             LOGD("IP third octet: " << thirdOctetStr);
1165             dynamicConfig.ipv4Gateway = boost::regex_replace(dynamicConfig.ipv4Gateway,
1166                                                              ZONE_IP_THIRD_OCTET_REGEX,
1167                                                              thirdOctetStr);
1168             dynamicConfig.ipv4 = boost::regex_replace(dynamicConfig.ipv4,
1169                                                       ZONE_IP_THIRD_OCTET_REGEX,
1170                                                       thirdOctetStr);
1171         }
1172     }
1173
1174     // save dynamic config
1175     config::saveToKVStore(mConfig.dbPath, dynamicConfig, dbPrefix);
1176
1177     // save zone template path
1178     ZoneTemplatePathConfig templatePathConfig;
1179     templatePathConfig.zoneTemplatePath = templatePath;
1180     config::saveToKVStore(mConfig.dbPath, templatePathConfig, dbPrefix);
1181
1182 }
1183
1184 int ZonesManager::getVTForNewZone()
1185 {
1186     if (mConfig.availableVTs.empty()) {
1187         return -1;
1188     }
1189     std::set<int> candidates(mConfig.availableVTs.begin(), mConfig.availableVTs.end());
1190     // exclude all used
1191     for (auto& zone : mZones) {
1192         candidates.erase(zone->getVT());
1193     }
1194     if (candidates.empty()) {
1195         const std::string msg = "No free VT for zone";
1196         LOGE(msg);
1197         throw ZoneOperationException(msg);
1198     }
1199     // return the smallest
1200     return *candidates.begin();
1201 }
1202
1203 void ZonesManager::createZone(const std::string& id,
1204                               const std::string& templateName)
1205 {
1206     if (id.empty() || !isalnum(id)) {
1207         const std::string msg = "Failed to add zone - invalid name.";
1208         LOGE(msg);
1209         throw InvalidZoneIdException(msg);
1210     }
1211
1212     if (find(prohibitedZonesNames.begin(), prohibitedZonesNames.end(), id) != prohibitedZonesNames.end()) {
1213         const std::string msg = "Cannot create " + id + " zone - name is not allowed!";
1214         LOGE(msg);
1215         throw InvalidZoneIdException(msg);
1216     }
1217
1218     LOGI("Creating zone " << id);
1219
1220     Lock lock(mMutex);
1221
1222     // TODO: This solution is temporary. It utilizes direct access to config files when creating new
1223     // zones. Update this handler when config database will appear.
1224     namespace fs = boost::filesystem;
1225
1226     // check if zone does not exist
1227     if (findZone(id) != mZones.end()) {
1228         const std::string msg = "Cannot create " + id + " zone - already exists!";
1229         LOGE(msg);
1230         throw InvalidZoneIdException(msg);
1231     }
1232
1233     if (fs::exists(fs::path(mConfig.zonesPath) / id)) {
1234         const std::string msg = "Cannot create " + id + " zone - file system already exists!";
1235         LOGE(msg);
1236         throw InvalidZoneIdException(msg);
1237     }
1238
1239     const std::string zonePathStr = utils::createFilePath(mConfig.zonesPath, id, "/");
1240
1241     // copy zone image if config contains path to image
1242     LOGT("Image path: " << mConfig.zoneImagePath);
1243     if (!mConfig.zoneImagePath.empty()) {
1244         auto copyImageContentsWrapper = std::bind(&utils::copyImageContents,
1245                                                   mConfig.zoneImagePath,
1246                                                   zonePathStr);
1247
1248         if (!utils::launchAsRoot(copyImageContentsWrapper)) {
1249             const std::string msg = "Failed to copy zone image.";
1250             LOGE(msg);
1251             throw ZoneOperationException(msg);
1252         }
1253     }
1254
1255     auto removeAllWrapper = [](const std::string & path) -> bool {
1256         try {
1257             LOGD("Removing copied data");
1258             fs::remove_all(fs::path(path));
1259         } catch (const std::exception& e) {
1260             LOGW("Failed to remove data: " << boost::diagnostic_information(e));
1261         }
1262         return true;
1263     };
1264
1265     std::string zoneTemplatePath = utils::createFilePath(mConfig.zoneTemplateDir,
1266                                                          templateName + ".conf");
1267
1268     try {
1269         LOGI("Generating config from " << zoneTemplatePath);
1270         generateNewConfig(id, zoneTemplatePath);
1271     } catch (std::runtime_error& e) {
1272         LOGE("Generate config failed: " << e.what());
1273         utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr));
1274         throw;
1275     }
1276
1277     LOGT("Creating new zone");
1278     try {
1279         insertZone(id, zoneTemplatePath);
1280     } catch (std::runtime_error& e) {
1281         LOGE("Creating new zone failed: " << e.what());
1282         utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr));
1283         throw;
1284     }
1285
1286     mDynamicConfig.zoneIds.push_back(id);
1287     saveDynamicConfig();
1288     updateDefaultId();
1289 }
1290
1291 void ZonesManager::handleCreateZoneCall(const api::CreateZoneIn& data,
1292                                         api::MethodResultBuilder::Pointer result)
1293 {
1294     auto creator = [&, this] {
1295         try {
1296             createZone(data.first, data.second);
1297             result->setVoid();
1298         } catch (const InvalidZoneIdException& e) {
1299             result->setError(api::ERROR_INVALID_ID, e.what());
1300         } catch (const std::exception& e) {
1301             result->setError(api::ERROR_INTERNAL, e.what());
1302         }
1303     };
1304
1305     tryAddTask(creator, result, true);
1306 }
1307
1308 void ZonesManager::handleDestroyZoneCall(const api::ZoneId& zoneId,
1309                                          api::MethodResultBuilder::Pointer result)
1310 {
1311     auto destroyer = [=] {
1312         try {
1313             LOGI("Destroying zone " << zoneId.value);
1314             destroyZone(zoneId.value);
1315         } catch (const InvalidZoneIdException&) {
1316             LOGE("Failed to destroy zone - no such zone id: " << zoneId.value);
1317             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1318         } catch (const std::runtime_error& e) {
1319             LOGE("Error during zone destruction: " << e.what());
1320             result->setError(api::ERROR_INTERNAL, "Failed to destroy zone");
1321             return;
1322         }
1323         result->setVoid();
1324     };
1325
1326     tryAddTask(destroyer, result, false);
1327 }
1328
1329 void ZonesManager::handleShutdownZoneCall(const api::ZoneId& zoneId,
1330                                           api::MethodResultBuilder::Pointer result)
1331 {
1332     auto shutdown = [=] {
1333         LOGI("ShutdownZone call; Id=" << zoneId.value);
1334
1335         try {
1336             LOGT("Shutdown zone " << zoneId.value);
1337
1338             Lock lock(mMutex);
1339             auto iter = findZone(zoneId.value);
1340             if (iter == mZones.end()) {
1341                 LOGE("Failed to shutdown zone - no such zone id: " << zoneId.value);
1342                 result->setError(api::ERROR_INVALID_ID, "No such zone id");
1343                 return;
1344             }
1345             get(iter).stop(true);
1346             refocus();
1347             result->setVoid();
1348         } catch (ZoneOperationException& e) {
1349             LOGE("Error during zone shutdown: " << e.what());
1350             result->setError(api::ERROR_INTERNAL, "Failed to shutdown zone");
1351             return;
1352         }
1353     };
1354
1355     tryAddTask(shutdown, result, false);
1356 }
1357
1358 void ZonesManager::handleStartZoneCall(const api::ZoneId& zoneId,
1359                                        api::MethodResultBuilder::Pointer result)
1360 {
1361     auto startAsync = [=] {
1362         LOGI("StartZone call; Id=" << zoneId.value);
1363
1364         try {
1365             LOGT("Start zone " << zoneId.value);
1366
1367             Lock lock(mMutex);
1368             auto iter = findZone(zoneId.value);
1369             if (iter == mZones.end()) {
1370                 LOGE("Failed to start zone - no such zone id: " << zoneId.value);
1371                 result->setError(api::ERROR_INVALID_ID, "No such zone id");
1372                 return;
1373             }
1374             get(iter).start();
1375             focusInternal(iter);
1376             result->setVoid();
1377         } catch (const std::exception& e) {
1378             LOGE(zoneId.value << ": failed to start: " << e.what());
1379             result->setError(api::ERROR_INTERNAL, "Failed to start zone");
1380         }
1381     };
1382     tryAddTask(startAsync, result, false);
1383 }
1384
1385 void ZonesManager::handleLockZoneCall(const api::ZoneId& zoneId,
1386                                       api::MethodResultBuilder::Pointer result)
1387 {
1388     auto handler = [&, this] {
1389         LOGI("LockZone call; Id=" << zoneId.value );
1390
1391         Lock lock(mMutex);
1392
1393         auto iter = findZone(zoneId.value);
1394         if (iter == mZones.end()) {
1395             LOGE("Failed to lock zone - no such zone id: " << zoneId.value);
1396             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1397             return;
1398         }
1399
1400         Zone& zone = get(iter);
1401         if (!zone.isRunning()) {
1402             LOGE("Zone id=" << zoneId.value << " is not running.");
1403             result->setError(api::ERROR_INVALID_STATE, "Zone is not running");
1404             return;
1405         }
1406
1407         LOGT("Lock zone");
1408         try {
1409             zone.goBackground();// make sure it will be in background after unlock
1410             zone.suspend();
1411             refocus();
1412         } catch (ZoneOperationException& e) {
1413             LOGE(e.what());
1414             result->setError(api::ERROR_INTERNAL, e.what());
1415             return;
1416         }
1417
1418         result->setVoid();
1419     };
1420
1421     tryAddTask(handler, result, true);
1422 }
1423
1424 void ZonesManager::handleUnlockZoneCall(const api::ZoneId& zoneId,
1425                                         api::MethodResultBuilder::Pointer result)
1426 {
1427     auto handler = [&, this] {
1428         LOGI("UnlockZone call; Id=" << zoneId.value );
1429
1430         Lock lock(mMutex);
1431
1432         auto iter = findZone(zoneId.value);
1433         if (iter == mZones.end()) {
1434             LOGE("Failed to unlock zone - no such zone id: " << zoneId.value);
1435             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1436             return;
1437         }
1438
1439         Zone& zone = get(iter);
1440         if (!zone.isPaused()) {
1441             LOGE("Zone id=" << zoneId.value << " is not paused.");
1442             result->setError(api::ERROR_INVALID_STATE, "Zone is not paused");
1443             return;
1444         }
1445
1446         LOGT("Unlock zone");
1447         try {
1448             zone.resume();
1449         } catch (ZoneOperationException& e) {
1450             LOGE(e.what());
1451             result->setError(api::ERROR_INTERNAL, e.what());
1452             return;
1453         }
1454
1455         result->setVoid();
1456     };
1457
1458     tryAddTask(handler, result, true);
1459 }
1460
1461 void ZonesManager::handleGrantDeviceCall(const api::GrantDeviceIn& data,
1462                                          api::MethodResultBuilder::Pointer result)
1463 {
1464     auto handler = [&, this] {
1465         LOGI("GrantDevice call; id=" << data.id << "; dev=" << data.device);
1466
1467         Lock lock(mMutex);
1468
1469         auto iter = findZone(data.id);
1470         if (iter == mZones.end()) {
1471             LOGE("Failed to grant device - no such zone id: " << data.id);
1472             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1473             return;
1474         }
1475
1476         Zone& zone = get(iter);
1477         if (!zone.isRunning() && !zone.isPaused()) {
1478             LOGE("Zone id=" << data.id << " is not running");
1479             result->setError(api::ERROR_INVALID_STATE, "Zone is not running");
1480             return;
1481         }
1482
1483         std::string devicePath = "/dev/" + data.device;
1484
1485         if (!lxc::isDevice(devicePath)) {
1486             LOGE("Failed to grant device - cannot acces device: " << data.device);
1487             result->setError(api::ERROR_FORBIDDEN, "Cannot access device");
1488             return;
1489         }
1490
1491         // assume device node is created inside zone
1492         if (!lxc::setDeviceAccess(data.id, devicePath, true, data.flags)) {
1493             LOGE("Failed to grant device: " << data.device << " for zone: " << data.id);
1494             result->setError(api::ERROR_INTERNAL, "Cannot grant device");
1495             return;
1496         }
1497
1498         result->setVoid();
1499     };
1500
1501     tryAddTask(handler, result, true);
1502 }
1503
1504 void ZonesManager::handleRevokeDeviceCall(const api::RevokeDeviceIn& data,
1505                                           api::MethodResultBuilder::Pointer result)
1506 {
1507     auto handler = [&, this] {
1508         LOGI("RevokeDevice call; id=" << data.first << "; dev=" << data.second);
1509
1510         Lock lock(mMutex);
1511
1512         auto iter = findZone(data.first);
1513         if (iter == mZones.end()) {
1514             LOGE("Failed to revoke device - no such zone id: " << data.first);
1515             result->setError(api::ERROR_INVALID_ID, "No such zone id");
1516             return;
1517         }
1518
1519         Zone& zone = get(iter);
1520         if (!zone.isRunning() && !zone.isPaused()) {
1521             LOGE("Zone id=" << data.first << " is not running");
1522             result->setError(api::ERROR_INVALID_STATE, "Zone is not running");
1523             return;
1524         }
1525         std::string devicePath = "/dev/" + data.second;
1526
1527         if (!lxc::isDevice(devicePath)) {
1528             LOGE("Failed to revoke device - cannot acces device: " << data.second);
1529             result->setError(api::ERROR_FORBIDDEN, "Cannot access device");
1530             return;
1531         }
1532
1533         if (!lxc::setDeviceAccess(data.first, devicePath, false, 0)) {
1534             LOGE("Failed to revoke device: " << data.second << " for zone: " << data.first);
1535             result->setError(api::ERROR_INTERNAL, "Cannot revoke device");
1536             return;
1537         }
1538
1539         result->setVoid();
1540     };
1541
1542     tryAddTask(handler, result, true);
1543 }
1544
1545 void ZonesManager::handleCleanUpZonesRootCall(api::MethodResultBuilder::Pointer result)
1546 {
1547     auto handler = [&, this] {
1548         LOGI("CleanUpZonesRoot call");
1549         try {
1550             std::vector<std::string> zonesIds;
1551             Lock lock(mMutex);
1552             for (const auto& zone : mZones) {
1553                 zonesIds.push_back(zone->getId());
1554             }
1555             cleanUpUnknownsFromRoot(mConfig.zonesPath, zonesIds, false);
1556         } catch (const std::exception& e) {
1557             result->setError(api::ERROR_INTERNAL, e.what());
1558         }
1559         result->setVoid();
1560     };
1561
1562     tryAddTask(handler, result, true);
1563 }
1564
1565 } // namespace vasum