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