15cccf6f118e9daa1f7a196bcee0a1fae7e79ec3
[platform/core/security/vasum.git] / client / vasum-client-impl.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Mateusz Malicki <m.malicki2@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19
20 /**
21  * @file
22  * @author  Mateusz Malicki (m.malicki2@samsung.com)
23  * @brief   This file contains vasum-server's client implementation
24  */
25
26 //TODO: Make dispatcher related function thread-safe.
27 //For now vsm_connect, vsm_get_dispatcher_type, vsm_set_dispatcher_type,
28 //vsm_get_poll_fd, vsm_enter_eventloop can't be used at the same time.
29 //TODO: Make vsm_get_status_message thread-safe version (vsm_get_status_message_r)
30
31 #include "config.hpp"
32 #include "vasum-client-impl.hpp"
33 #include "utils.hpp"
34 #include "exception.hpp"
35 #include "utils/exception.hpp"
36 #include "logger/logger.hpp"
37 #include "host-ipc-definitions.hpp"
38 #include "ipc/client.hpp"
39 #include "api/messages.hpp"
40
41 #include <algorithm>
42 #include <vector>
43 #include <memory>
44 #include <cstring>
45 #include <fstream>
46 #include <arpa/inet.h>
47 #include <linux/if.h>
48
49 #include <boost/algorithm/string/split.hpp>
50 #include <boost/algorithm/string/classification.hpp>
51
52 using namespace std;
53 using namespace utils;
54 using namespace vasum;
55
56 namespace {
57
58 const int TIMEOUT_INFINITE = -1;
59
60 VsmZoneState getZoneState(const char* state)
61 {
62     if (strcmp(state, "STOPPED") == 0) {
63         return STOPPED;
64     } else if (strcmp(state, "STARTING") == 0) {
65         return STARTING;
66     } else if (strcmp(state, "RUNNING") == 0) {
67         return RUNNING;
68     } else if (strcmp(state, "STOPPING") == 0) {
69         return STOPPING;
70     } else if (strcmp(state, "ABORTING") == 0) {
71         return ABORTING;
72     } else if (strcmp(state, "FREEZING") == 0) {
73         return FREEZING;
74     } else if (strcmp(state, "FROZEN") == 0) {
75         return FROZEN;
76     } else if (strcmp(state, "THAWED") == 0) {
77         return THAWED;
78     } else if (strcmp(state, "LOCKED") == 0) {
79         return LOCKED;
80     } else if (strcmp(state, "MAX_STATE") == 0) {
81         return MAX_STATE;
82     } else if (strcmp(state, "ACTIVATING") == 0) {
83         return ACTIVATING;
84     }
85     throw InvalidResponseException("Unknown state");
86 }
87
88 void convert(const api::VectorOfStrings& in, VsmArrayString& out)
89 {
90     out = reinterpret_cast<char**>(calloc(in.values.size() + 1, sizeof(char*)));
91     for (size_t i = 0; i < in.values.size(); ++i) {
92         out[i] = ::strdup(in.values[i].c_str());
93     }
94 }
95
96 void convert(const api::ZoneInfoOut& info, Zone& zone)
97 {
98     Zone vsmZone = static_cast<Zone>(malloc(sizeof(*vsmZone)));
99     vsmZone->id = ::strdup(info.id.c_str());
100     vsmZone->terminal = info.vt;
101     vsmZone->state = getZoneState(info.state.c_str());
102     vsmZone->rootfs_path = ::strdup(info.rootPath.c_str());
103     zone = vsmZone;
104 }
105
106 string toString(const in_addr* addr)
107 {
108     char buf[INET_ADDRSTRLEN];
109     const char* ret = inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN);
110     if (ret == NULL) {
111         throw InvalidArgumentException(getSystemErrorMessage());
112     }
113     return ret;
114 }
115
116 string toString(const in6_addr* addr)
117 {
118     char buf[INET6_ADDRSTRLEN];
119     const char* ret = inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN);
120     if (ret == NULL) {
121         throw InvalidArgumentException(getSystemErrorMessage());
122     }
123     return ret;
124 }
125
126 bool readFirstLineOfFile(const string& path, string& ret)
127 {
128     ifstream file(path);
129     if (!file) {
130         return false;
131     }
132
133     getline(file, ret);
134     return true;
135 }
136
137 } //namespace
138
139 #define IS_SET(param)                                            \
140     if (!param) {                                                \
141         throw InvalidArgumentException(#param " is not set");    \
142     }
143
144 Client::Status::Status()
145     : mVsmStatus(VSMCLIENT_SUCCESS), mMsg()
146 {
147 }
148
149 Client::Status::Status(VsmStatus status, const string& msg)
150     : mVsmStatus(status), mMsg(msg)
151 {
152 }
153
154 Client::Client() noexcept
155 {
156 }
157
158 Client::~Client() noexcept
159 {
160 }
161
162 bool Client::isConnected() const
163 {
164     return mClient && mClient->isStarted();
165 }
166
167 bool Client::isInternalDispatcherEnabled() const
168 {
169     return static_cast<bool>(mInternalDispatcher);
170 }
171
172 ipc::epoll::EventPoll& Client::getEventPoll() const
173 {
174     if ((mInternalDispatcher && mEventPoll) || (!mInternalDispatcher && !mEventPoll)) {
175         throw OperationFailedException("Can't determine dispatcher method");
176     }
177
178     if (isInternalDispatcherEnabled()) {
179         return mInternalDispatcher->getPoll();
180     } else {
181         return *mEventPoll;
182     }
183 }
184
185 VsmStatus Client::coverException(const function<void(void)>& worker) noexcept
186 {
187     try {
188         worker();
189         mStatusMutex.lock();
190         mStatus = Status(VSMCLIENT_SUCCESS);
191     } catch (const IOException& ex) {
192         mStatus = Status(VSMCLIENT_IO_ERROR, ex.what());
193     } catch (const OperationFailedException& ex) {
194         mStatus = Status(VSMCLIENT_OPERATION_FAILED, ex.what());
195     } catch (const InvalidArgumentException& ex) {
196         mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what());
197     } catch (const InvalidResponseException& ex) {
198         mStatus = Status(VSMCLIENT_OTHER_ERROR, ex.what());
199     } catch (const ClientException& ex) {
200         mStatus = Status(VSMCLIENT_CUSTOM_ERROR, ex.what());
201     } catch (const ipc::IPCUserException& ex) {
202         mStatus = Status(VSMCLIENT_CUSTOM_ERROR, ex.what());
203     } catch (const ipc::IPCException& ex) {
204         mStatus = Status(VSMCLIENT_IO_ERROR, ex.what());
205     } catch (const exception& ex) {
206         mStatus = Status(VSMCLIENT_CUSTOM_ERROR, ex.what());
207     }
208     VsmStatus ret = mStatus.mVsmStatus;
209     mStatusMutex.unlock();
210     return ret;
211 }
212
213 VsmStatus Client::connectSystem() noexcept
214 {
215     return connect(HOST_IPC_SOCKET);
216 }
217
218 VsmStatus Client::connect(const std::string& address) noexcept
219 {
220     return coverException([&] {
221         if (!mInternalDispatcher && !mEventPoll) {
222             vsm_set_dispatcher_type(VSMDISPATCHER_INTERNAL);
223         }
224         mClient.reset(new ipc::Client(getEventPoll(), address));
225         mClient->start();
226     });
227 }
228
229 VsmStatus Client::disconnect() noexcept
230 {
231     return coverException([&] {
232         mClient.reset();
233     });
234 }
235
236 VsmStatus Client::vsm_get_poll_fd(int* fd) noexcept
237 {
238     return coverException([&] {
239         IS_SET(fd);
240         if (isInternalDispatcherEnabled()) {
241             throw OperationFailedException("Can't get event fd from internal dispatcher");
242         }
243         *fd =  mEventPoll->getPollFD();
244     });
245 }
246
247 VsmStatus Client::vsm_enter_eventloop(int /* flags */, int timeout) noexcept
248 {
249     return coverException([&] {
250         if (isInternalDispatcherEnabled()) {
251             throw OperationFailedException("Can't enter to event loop of internal dispatcher");
252         }
253         mEventPoll->dispatchIteration(timeout);
254     });
255 }
256
257 VsmStatus Client::vsm_set_dispatcher_type(VsmDispacherType dispacher) noexcept
258 {
259     return coverException([&] {
260         if (isConnected()) {
261             throw OperationFailedException("Can't change dispacher");
262         }
263         switch (dispacher) {
264             case VSMDISPATCHER_INTERNAL:
265                 mInternalDispatcher.reset(new ipc::epoll::ThreadDispatcher());
266                 mEventPoll.reset();
267                 break;
268             case VSMDISPATCHER_EXTERNAL:
269                 mEventPoll.reset(new ipc::epoll::EventPoll());
270                 mInternalDispatcher.reset();
271                 break;
272             default:
273                 throw OperationFailedException("Unsupported EventDispacher type");
274         }
275     });
276 }
277
278 VsmStatus Client::vsm_get_dispatcher_type(VsmDispacherType* dispacher) noexcept
279 {
280     return coverException([&] {
281         IS_SET(dispacher);
282
283         if (isInternalDispatcherEnabled()) {
284             *dispacher = VSMDISPATCHER_INTERNAL;
285         } else {
286             *dispacher = VSMDISPATCHER_EXTERNAL;
287         }
288     });
289 }
290
291 const char* Client::vsm_get_status_message() const noexcept
292 {
293     return mStatus.mMsg.c_str();
294 }
295
296 VsmStatus Client::vsm_get_status() const noexcept
297 {
298     lock_guard<mutex> lock(mStatusMutex);
299     return mStatus.mVsmStatus;
300 }
301
302 VsmStatus Client::vsm_get_zone_dbuses(VsmArrayString* /*keys*/, VsmArrayString* /*values*/) noexcept
303 {
304     return coverException([&] {
305         //TODO: Remove vsm_get_zone_dbuses from API
306         throw OperationFailedException("Not implemented");
307     });
308 }
309
310 VsmStatus Client::vsm_lock_queue() noexcept
311 {
312     return coverException([&] {
313         *mClient->callSync<api::Void, api::Void>(
314             vasum::api::ipc::METHOD_LOCK_QUEUE,
315             std::make_shared<api::Void>());
316     });
317 }
318
319 VsmStatus Client::vsm_unlock_queue() noexcept
320 {
321     return coverException([&] {
322         *mClient->callSync<api::Void, api::Void>(
323             vasum::api::ipc::METHOD_UNLOCK_QUEUE,
324             std::make_shared<api::Void>());
325     });
326 }
327
328 VsmStatus Client::vsm_get_zone_ids(VsmArrayString* array) noexcept
329 {
330     return coverException([&] {
331         IS_SET(array);
332
333         api::ZoneIds zoneIds = *mClient->callSync<api::Void, api::ZoneIds>(
334             vasum::api::ipc::METHOD_GET_ZONE_ID_LIST,
335             std::make_shared<api::Void>());
336         convert(zoneIds, *array);
337     });
338 }
339
340 VsmStatus Client::vsm_get_active_zone_id(VsmString* id) noexcept
341 {
342     return coverException([&] {
343         IS_SET(id);
344
345         api::ZoneId zoneId = *mClient->callSync<api::Void, api::ZoneId>(
346             api::ipc::METHOD_GET_ACTIVE_ZONE_ID,
347             std::make_shared<api::Void>());
348         *id = ::strdup(zoneId.value.c_str());
349     });
350 }
351
352 VsmStatus Client::vsm_lookup_zone_by_pid(int pid, VsmString* id) noexcept
353 {
354     return coverException([&] {
355         IS_SET(id);
356
357         const string path = "/proc/" + to_string(pid) + "/cpuset";
358
359         string cpuset;
360         if (!readFirstLineOfFile(path, cpuset)) {
361             throw InvalidArgumentException("Process not found");
362         }
363
364         string zoneId;
365         if (!parseZoneIdFromCpuSet(cpuset, zoneId)) {
366             throw OperationFailedException("unknown format of cpuset");
367         }
368
369         *id = ::strdup(zoneId.c_str());
370     });
371 }
372
373 VsmStatus Client::vsm_lookup_zone_by_id(const char* id, Zone* zone) noexcept
374 {
375     return coverException([&] {
376         IS_SET(id);
377         IS_SET(zone);
378
379         api::ZoneInfoOut info = *mClient->callSync<api::ZoneId, api::ZoneInfoOut>(
380             api::ipc::METHOD_GET_ZONE_INFO,
381             std::make_shared<api::ZoneId>(api::ZoneId{ id }));
382         convert(info, *zone);
383     });
384 }
385
386 VsmStatus Client::vsm_lookup_zone_by_terminal_id(int, VsmString*) noexcept
387 {
388     return coverException([&] {
389         //TODO: Implement vsm_lookup_zone_by_terminal_id
390         throw OperationFailedException("Not implemented");
391     });
392 }
393
394 VsmStatus Client::vsm_set_active_zone(const char* id) noexcept
395 {
396     return coverException([&] {
397         IS_SET(id);
398
399         mClient->callSync<api::ZoneId, api::Void>(
400             api::ipc::METHOD_SET_ACTIVE_ZONE,
401             std::make_shared<api::ZoneId>(api::ZoneId{ id }));
402     });
403 }
404
405 VsmStatus Client::vsm_create_zone(const char* id, const char* tname) noexcept
406 {
407     return coverException([&] {
408         IS_SET(id);
409
410         string template_name = tname ? tname : "default";
411         mClient->callSync<api::CreateZoneIn, api::Void>(
412             api::ipc::METHOD_CREATE_ZONE,
413             std::make_shared<api::CreateZoneIn>(api::CreateZoneIn{ id, template_name }),
414             TIMEOUT_INFINITE);
415     });
416 }
417
418 VsmStatus Client::vsm_destroy_zone(const char* id) noexcept
419 {
420     return coverException([&] {
421         IS_SET(id);
422         mClient->callSync<api::ZoneId, api::Void>(
423             api::ipc::METHOD_DESTROY_ZONE,
424             std::make_shared<api::ZoneId>(api::ZoneId{ id }),
425             TIMEOUT_INFINITE);
426     });
427 }
428
429 VsmStatus Client::vsm_shutdown_zone(const char* id) noexcept
430 {
431     return coverException([&] {
432         IS_SET(id);
433         mClient->callSync<api::ZoneId, api::Void>(
434             api::ipc::METHOD_SHUTDOWN_ZONE,
435             std::make_shared<api::ZoneId>(api::ZoneId{ id }),
436             TIMEOUT_INFINITE);
437     });
438 }
439
440 VsmStatus Client::vsm_start_zone(const char* id) noexcept
441 {
442     return coverException([&] {
443         IS_SET(id);
444         mClient->callSync<api::ZoneId, api::Void>(
445             api::ipc::METHOD_START_ZONE,
446             std::make_shared<api::ZoneId>(api::ZoneId{ id }),
447             TIMEOUT_INFINITE);
448     });
449 }
450
451 VsmStatus Client::vsm_lock_zone(const char* id) noexcept
452 {
453     return coverException([&] {
454         IS_SET(id);
455         mClient->callSync<api::ZoneId, api::Void>(
456             api::ipc::METHOD_LOCK_ZONE,
457             std::make_shared<api::ZoneId>(api::ZoneId{ id }),
458             TIMEOUT_INFINITE);
459     });
460 }
461
462 VsmStatus Client::vsm_unlock_zone(const char* id) noexcept
463 {
464     return coverException([&] {
465         IS_SET(id);
466         mClient->callSync<api::ZoneId, api::Void>(
467             api::ipc::METHOD_UNLOCK_ZONE,
468             std::make_shared<api::ZoneId>(api::ZoneId{ id }));
469     });
470 }
471
472 VsmStatus Client::vsm_add_state_callback(VsmZoneDbusStateFunction /* zoneDbusStateCallback */,
473                                     void* /* data */,
474                                     VsmSubscriptionId* /* subscriptionId */) noexcept
475 {
476     return coverException([&] {
477         //TODO: Implement vsm_add_state_callback
478         throw OperationFailedException("Not implemented");
479     });
480 }
481
482 VsmStatus Client::vsm_del_state_callback(VsmSubscriptionId subscriptionId) noexcept
483 {
484     return coverException([&] {
485         mClient->removeMethod(subscriptionId);
486     });
487 }
488
489 VsmStatus Client::vsm_grant_device(const char* id, const char* device, uint32_t flags) noexcept
490 {
491     return coverException([&] {
492         IS_SET(id);
493         IS_SET(device);
494
495         mClient->callSync<api::GrantDeviceIn, api::Void>(
496             api::ipc::METHOD_GRANT_DEVICE,
497             std::make_shared<api::GrantDeviceIn>(api::GrantDeviceIn{ id, device, flags }));
498     });
499 }
500
501 VsmStatus Client::vsm_revoke_device(const char* id, const char* device) noexcept
502 {
503     return coverException([&] {
504         IS_SET(id);
505         IS_SET(device);
506
507         mClient->callSync<api::RevokeDeviceIn, api::Void>(
508             api::ipc::METHOD_REVOKE_DEVICE,
509             std::make_shared<api::RevokeDeviceIn>(api::RevokeDeviceIn{ id, device }));
510     });
511 }
512
513 VsmStatus Client::vsm_zone_get_netdevs(const char* id, VsmArrayString* netdevIds) noexcept
514 {
515     return coverException([&] {
516         IS_SET(id);
517         IS_SET(netdevIds);
518
519         api::NetDevList netdevs = *mClient->callSync<api::ZoneId, api::NetDevList>(
520             api::ipc::METHOD_GET_NETDEV_LIST,
521             std::make_shared<api::ZoneId>(api::ZoneId{ id }));
522         convert(netdevs, *netdevIds);
523     });
524 }
525
526 VsmStatus Client::vsm_netdev_get_ip_addr(const char* id,
527                                          const char* netdevId,
528                                          int type,
529                                          void* addr) noexcept
530 {
531     using namespace boost::algorithm;
532
533     return coverException([&] {
534         IS_SET(id);
535         IS_SET(netdevId);
536         IS_SET(addr);
537
538         api::GetNetDevAttrs attrs = *mClient->callSync<api::GetNetDevAttrsIn, api::GetNetDevAttrs>(
539             api::ipc::METHOD_GET_NETDEV_ATTRS,
540             std::make_shared<api::GetNetDevAttrsIn>(api::GetNetDevAttrsIn{ id, netdevId }));
541
542         auto it = find_if(attrs.values.begin(),
543                           attrs.values.end(),
544                           [type](const api::StringPair& entry) {
545                 return entry.first == (type == AF_INET ? "ipv4" : "ipv6");
546         });
547
548         if (it != attrs.values.end()) {
549             vector<string> addrAttrs;
550             for(auto addrAttr : split(addrAttrs, it->second, is_any_of(","))) {
551                 size_t pos = addrAttr.find(":");
552                 if (addrAttr.substr(0, pos) == "ip") {
553                     if (pos != string::npos && pos < addrAttr.length() &&
554                         inet_pton(type, addrAttr.substr(pos + 1).c_str(), addr) == 1) {
555                         //XXX: return only one address
556                         return;
557                     } else {
558                         throw InvalidResponseException("Wrong address format returned");
559                     }
560                 }
561             }
562         }
563         throw OperationFailedException("Address not found");
564     });
565 }
566
567 VsmStatus Client::vsm_netdev_get_ipv4_addr(const char* id,
568                                       const char* netdevId,
569                                       struct in_addr* addr) noexcept
570 {
571     return vsm_netdev_get_ip_addr(id, netdevId, AF_INET, addr);
572 }
573
574 VsmStatus Client::vsm_netdev_get_ipv6_addr(const char* id,
575                                       const char* netdevId,
576                                       struct in6_addr* addr) noexcept
577 {
578     return vsm_netdev_get_ip_addr(id, netdevId, AF_INET6, addr);
579 }
580
581 VsmStatus Client::vsm_netdev_set_ipv4_addr(const char* id,
582                                       const char* netdevId,
583                                       struct in_addr* addr,
584                                       int prefix) noexcept
585 {
586     return coverException([&] {
587         IS_SET(id);
588         IS_SET(netdevId);
589         IS_SET(addr);
590
591         string value = "ip:" + toString(addr) + ",""prefixlen:" + to_string(prefix);
592         mClient->callSync<api::SetNetDevAttrsIn, api::Void>(
593             api::ipc::METHOD_SET_NETDEV_ATTRS,
594             std::make_shared<api::SetNetDevAttrsIn>(
595                 api::SetNetDevAttrsIn{ id, netdevId, { { "ipv4", value } }  }));
596     });
597 }
598
599 VsmStatus Client::vsm_netdev_set_ipv6_addr(const char* id,
600                                       const char* netdevId,
601                                       struct in6_addr* addr,
602                                       int prefix) noexcept
603 {
604     return coverException([&] {
605         IS_SET(id);
606         IS_SET(netdevId);
607         IS_SET(addr);
608
609         string value = "ip:" + toString(addr) + ",""prefixlen:" + to_string(prefix);
610         mClient->callSync<api::SetNetDevAttrsIn, api::Void>(
611             api::ipc::METHOD_SET_NETDEV_ATTRS,
612             std::make_shared<api::SetNetDevAttrsIn>(
613                 api::SetNetDevAttrsIn{ id, netdevId, { { "ipv6", value } }  }));
614     });
615 }
616
617 VsmStatus Client::vsm_netdev_del_ipv4_addr(const char* id,
618                                       const char* netdevId,
619                                       struct in_addr* addr,
620                                       int prefix) noexcept
621 {
622     return coverException([&] {
623         IS_SET(id);
624         IS_SET(netdevId);
625         IS_SET(addr);
626
627         //CIDR notation
628         string ip = toString(addr) + "/" + to_string(prefix);
629         mClient->callSync<api::DeleteNetdevIpAddressIn, api::Void>(
630             api::ipc::METHOD_DELETE_NETDEV_IP_ADDRESS,
631             std::make_shared<api::DeleteNetdevIpAddressIn>(
632                 api::DeleteNetdevIpAddressIn{ id, netdevId, ip }));
633     });
634 }
635
636 VsmStatus Client::vsm_netdev_del_ipv6_addr(const char* id,
637                                       const char* netdevId,
638                                       struct in6_addr* addr,
639                                       int prefix) noexcept
640 {
641     return coverException([&] {
642         IS_SET(id);
643         IS_SET(netdevId);
644         IS_SET(addr);
645
646         //CIDR notation
647         string ip = toString(addr) + "/" + to_string(prefix);
648         mClient->callSync<api::DeleteNetdevIpAddressIn, api::Void>(
649             api::ipc::METHOD_DELETE_NETDEV_IP_ADDRESS,
650             std::make_shared<api::DeleteNetdevIpAddressIn>(
651                 api::DeleteNetdevIpAddressIn{ id, netdevId, ip }));
652     });
653 }
654
655
656 VsmStatus Client::vsm_netdev_up(const char* id, const char* netdevId) noexcept
657 {
658     return coverException([&] {
659         IS_SET(id);
660         IS_SET(netdevId);
661
662         mClient->callSync<api::SetNetDevAttrsIn, api::Void>(
663             api::ipc::METHOD_SET_NETDEV_ATTRS,
664             std::make_shared<api::SetNetDevAttrsIn>(
665                 api::SetNetDevAttrsIn{ id, netdevId, { { "flags", to_string(IFF_UP) },
666                                                        { "change", to_string(IFF_UP) }  }  }));
667     });
668 }
669
670 VsmStatus Client::vsm_netdev_down(const char* id, const char* netdevId) noexcept
671 {
672     return coverException([&] {
673         IS_SET(id);
674         IS_SET(netdevId);
675
676         mClient->callSync<api::SetNetDevAttrsIn, api::Void>(
677             api::ipc::METHOD_SET_NETDEV_ATTRS,
678             std::make_shared<api::SetNetDevAttrsIn>(
679                 api::SetNetDevAttrsIn{ id, netdevId, { { "flags", to_string(~IFF_UP) },
680                                                        { "change", to_string(IFF_UP) }  }  }));
681     });
682 }
683
684 VsmStatus Client::vsm_create_netdev_veth(const char* id,
685                                     const char* zoneDev,
686                                     const char* hostDev) noexcept
687 {
688     return coverException([&] {
689         IS_SET(id);
690         IS_SET(zoneDev);
691         IS_SET(hostDev);
692
693         mClient->callSync<api::CreateNetDevVethIn, api::Void>(
694             api::ipc::METHOD_CREATE_NETDEV_VETH,
695             std::make_shared<api::CreateNetDevVethIn>(
696                 api::CreateNetDevVethIn{ id, zoneDev, hostDev }));
697     });
698 }
699
700 VsmStatus Client::vsm_create_netdev_macvlan(const char* id,
701                                        const char* zoneDev,
702                                        const char* hostDev,
703                                        enum macvlan_mode mode) noexcept
704 {
705     return coverException([&] {
706         IS_SET(id);
707         IS_SET(zoneDev);
708         IS_SET(hostDev);
709
710         mClient->callSync<api::CreateNetDevMacvlanIn, api::Void>(
711             api::ipc::METHOD_CREATE_NETDEV_MACVLAN,
712             std::make_shared<api::CreateNetDevMacvlanIn>(
713                 api::CreateNetDevMacvlanIn{ id, zoneDev, hostDev, mode }));
714     });
715 }
716
717 VsmStatus Client::vsm_create_netdev_phys(const char* id, const char* devId) noexcept
718 {
719     return coverException([&] {
720         IS_SET(id);
721         IS_SET(devId);
722
723         mClient->callSync<api::CreateNetDevPhysIn, api::Void>(
724             api::ipc::METHOD_CREATE_NETDEV_PHYS,
725             std::make_shared<api::CreateNetDevPhysIn>(
726                 api::CreateNetDevPhysIn{ id, devId }));
727     });
728 }
729
730 VsmStatus Client::vsm_lookup_netdev_by_name(const char* id,
731                                        const char* netdevId,
732                                        Netdev* netdev) noexcept
733 {
734     using namespace boost::algorithm;
735
736     return coverException([&] {
737         IS_SET(id);
738         IS_SET(netdevId);
739         IS_SET(netdev);
740
741         api::GetNetDevAttrs attrs = *mClient->callSync<api::GetNetDevAttrsIn, api::GetNetDevAttrs>(
742             api::ipc::METHOD_GET_NETDEV_ATTRS,
743             std::make_shared<api::GetNetDevAttrsIn>(api::GetNetDevAttrsIn{ id, netdevId }));
744         auto it = find_if(attrs.values.begin(),
745                           attrs.values.end(),
746                           [](const api::StringPair& entry) {
747                 return entry.first == "type";
748         });
749
750         VsmNetdevType type;
751         if (it == attrs.values.end()) {
752             throw OperationFailedException("Can't fetch netdev type");
753         }
754
755         switch (stoi(it->second)) {
756             case 1<<0  /*IFF_802_1Q_VLAN*/: type = VSMNETDEV_VETH; break;
757             case 1<<21 /*IFF_MACVLAN*/: type = VSMNETDEV_MACVLAN; break;
758             default:
759                 throw InvalidResponseException("Unknown netdev type: " + it->second);
760         }
761
762         *netdev = static_cast<Netdev>(malloc(sizeof(**netdev)));
763         (*netdev)->name = ::strdup(id);
764         (*netdev)->type = type;
765     });
766 }
767
768 VsmStatus Client::vsm_destroy_netdev(const char* id, const char* devId) noexcept
769 {
770     return coverException([&] {
771         IS_SET(id);
772         IS_SET(devId);
773
774         mClient->callSync<api::DestroyNetDevIn, api::Void>(
775             api::ipc::METHOD_DESTROY_NETDEV,
776             std::make_shared<api::DestroyNetDevIn>(api::DestroyNetDevIn{ id, devId }));
777     });
778 }
779
780 VsmStatus Client::vsm_declare_file(const char* id,
781                               VsmFileType type,
782                               const char *path,
783                               int32_t flags,
784                               mode_t mode,
785                               VsmString* declarationId) noexcept
786 {
787     return coverException([&] {
788         IS_SET(id);
789         IS_SET(path);
790
791         api::Declaration declaration = *mClient->callSync<api::DeclareFileIn, api::Declaration>(
792             api::ipc::METHOD_DECLARE_FILE,
793             std::make_shared<api::DeclareFileIn>(
794                 api::DeclareFileIn{ id, type, path, flags, (int)mode }));
795         if (declarationId != NULL) {
796             *declarationId = ::strdup(declaration.value.c_str());
797         }
798     });
799 }
800
801 VsmStatus Client::vsm_declare_mount(const char *source,
802                                const char* id,
803                                const char *target,
804                                const char *type,
805                                uint64_t flags,
806                                const char *data,
807                                VsmString* declarationId) noexcept
808 {
809     return coverException([&] {
810         IS_SET(source);
811         IS_SET(id);
812         IS_SET(target);
813         IS_SET(type);
814         if (!data) {
815             data = "";
816         }
817
818         api::Declaration declaration = *mClient->callSync<api::DeclareMountIn, api::Declaration>(
819             api::ipc::METHOD_DECLARE_MOUNT,
820             std::make_shared<api::DeclareMountIn>(
821                 api::DeclareMountIn{ source, id, target, type, flags, data }));
822         if (declarationId != NULL) {
823             *declarationId = ::strdup(declaration.value.c_str());
824         }
825     });
826 }
827
828 VsmStatus Client::vsm_declare_link(const char* source,
829                               const char* id,
830                               const char* target,
831                               VsmString* declarationId) noexcept
832 {
833     return coverException([&] {
834         IS_SET(source);
835         IS_SET(id);
836         IS_SET(target);
837
838         api::Declaration declaration = *mClient->callSync<api::DeclareLinkIn, api::Declaration>(
839             api::ipc::METHOD_DECLARE_LINK,
840             std::make_shared<api::DeclareLinkIn>(api::DeclareLinkIn{ source, id, target }));
841         if (declarationId != NULL) {
842             *declarationId = ::strdup(declaration.value.c_str());
843         }
844     });
845 }
846
847 VsmStatus Client::vsm_list_declarations(const char* id, VsmArrayString* declarations) noexcept
848 {
849     return coverException([&] {
850         IS_SET(id);
851         IS_SET(declarations);
852
853         api::Declarations declarationsOut = *mClient->callSync<api::ZoneId, api::Declarations>(
854             api::ipc::METHOD_GET_DECLARATIONS,
855             std::make_shared<api::ZoneId>(api::ZoneId{ id }));
856         convert(declarationsOut, *declarations);
857     });
858 }
859
860 VsmStatus Client::vsm_remove_declaration(const char* id, VsmString declaration) noexcept
861 {
862     return coverException([&] {
863         IS_SET(id);
864         IS_SET(declaration);
865
866         mClient->callSync<api::RemoveDeclarationIn, api::Void>(
867             api::ipc::METHOD_REMOVE_DECLARATION,
868             std::make_shared<api::RemoveDeclarationIn>(api::RemoveDeclarationIn{ id, declaration }));
869     });
870 }
871
872 VsmStatus Client::vsm_clean_up_zones_root() noexcept
873 {
874     return coverException([&] {
875         mClient->callSync<api::Void, api::Void>(
876             api::ipc::METHOD_CLEAN_UP_ZONES_ROOT,
877             std::make_shared<api::Void>());
878     });
879 }
880