Support getting list of ip/mask for one interface, change netdev_set_ip* to netdev_ad...
[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                                          std::vector<InetAddr>& addrs) noexcept
529 {
530     using namespace boost::algorithm;
531
532     return coverException([&] {
533         IS_SET(id);
534         IS_SET(netdevId);
535
536         addrs.clear();
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         for (const auto &attr : attrs.values) {
543             InetAddr addr;
544             if (attr.first == "ipv4") {
545                 addr.type = AF_INET;
546             }
547             else if (attr.first == "ipv6") {
548                 addr.type = AF_INET6;
549             }
550             else continue;
551
552             std::vector<std::string> addrAttrs;
553             for(const auto& addrAttr : split(addrAttrs, attr.second, is_any_of(","))) {
554                 size_t pos = addrAttr.find(":");
555                 if (pos == string::npos) continue;
556
557                 if (addrAttr.substr(0, pos) == "prefixlen") {
558                     addr.prefix = atoi(addrAttr.substr(pos + 1).c_str());
559                 }
560                 else if (addrAttr.substr(0, pos) == "ip") {
561                     if (inet_pton(addr.type, addrAttr.substr(pos + 1).c_str(), &addr.addr) != 1) {
562                         addr.type = -1;
563                         break;
564                     }
565                 }
566             }
567             if (addr.type >= 0)
568                 addrs.push_back(addr);
569         }
570     });
571 }
572
573 VsmStatus Client::vsm_netdev_get_ipv4_addr(const char* id,
574                                       const char* netdevId,
575                                       struct in_addr* addr) noexcept
576 {
577     std::vector<InetAddr> addrs;
578     VsmStatus st=vsm_netdev_get_ip_addr(id, netdevId, addrs);
579     for (const auto& a : addrs) {
580         if (a.type == AF_INET) {
581             memcpy(addr, &a.addr, sizeof(*addr));
582             break;
583         }
584     }
585     return st;
586 }
587
588 VsmStatus Client::vsm_netdev_get_ipv6_addr(const char* id,
589                                       const char* netdevId,
590                                       struct in6_addr* addr) noexcept
591 {
592     std::vector<InetAddr> addrs;
593     VsmStatus st=vsm_netdev_get_ip_addr(id, netdevId, addrs);
594     for (const auto& a : addrs) {
595         if (a.type == AF_INET6) {
596             memcpy(addr, &a.addr, sizeof(*addr));
597             break;
598         }
599     }
600     return st;
601 }
602
603 VsmStatus Client::vsm_netdev_add_ipv4_addr(const char* id,
604                                       const char* netdevId,
605                                       struct in_addr* addr,
606                                       int prefix) noexcept
607 {
608     return coverException([&] {
609         IS_SET(id);
610         IS_SET(netdevId);
611         IS_SET(addr);
612
613         string value = "ip:" + toString(addr) + ",""prefixlen:" + to_string(prefix);
614         mClient->callSync<api::SetNetDevAttrsIn, api::Void>(
615             api::ipc::METHOD_SET_NETDEV_ATTRS,
616             std::make_shared<api::SetNetDevAttrsIn>(
617                 api::SetNetDevAttrsIn{ id, netdevId, { { "ipv4", value } }  }));
618     });
619 }
620
621 VsmStatus Client::vsm_netdev_add_ipv6_addr(const char* id,
622                                       const char* netdevId,
623                                       struct in6_addr* addr,
624                                       int prefix) noexcept
625 {
626     return coverException([&] {
627         IS_SET(id);
628         IS_SET(netdevId);
629         IS_SET(addr);
630
631         string value = "ip:" + toString(addr) + ",""prefixlen:" + to_string(prefix);
632         mClient->callSync<api::SetNetDevAttrsIn, api::Void>(
633             api::ipc::METHOD_SET_NETDEV_ATTRS,
634             std::make_shared<api::SetNetDevAttrsIn>(
635                 api::SetNetDevAttrsIn{ id, netdevId, { { "ipv6", value } }  }));
636     });
637 }
638
639 VsmStatus Client::vsm_netdev_del_ipv4_addr(const char* id,
640                                       const char* netdevId,
641                                       struct in_addr* addr,
642                                       int prefix) noexcept
643 {
644     return coverException([&] {
645         IS_SET(id);
646         IS_SET(netdevId);
647         IS_SET(addr);
648
649         //CIDR notation
650         string ip = toString(addr) + "/" + to_string(prefix);
651         mClient->callSync<api::DeleteNetdevIpAddressIn, api::Void>(
652             api::ipc::METHOD_DELETE_NETDEV_IP_ADDRESS,
653             std::make_shared<api::DeleteNetdevIpAddressIn>(
654                 api::DeleteNetdevIpAddressIn{ id, netdevId, ip }));
655     });
656 }
657
658 VsmStatus Client::vsm_netdev_del_ipv6_addr(const char* id,
659                                       const char* netdevId,
660                                       struct in6_addr* addr,
661                                       int prefix) noexcept
662 {
663     return coverException([&] {
664         IS_SET(id);
665         IS_SET(netdevId);
666         IS_SET(addr);
667
668         //CIDR notation
669         string ip = toString(addr) + "/" + to_string(prefix);
670         mClient->callSync<api::DeleteNetdevIpAddressIn, api::Void>(
671             api::ipc::METHOD_DELETE_NETDEV_IP_ADDRESS,
672             std::make_shared<api::DeleteNetdevIpAddressIn>(
673                 api::DeleteNetdevIpAddressIn{ id, netdevId, ip }));
674     });
675 }
676
677
678 VsmStatus Client::vsm_netdev_up(const char* id, const char* netdevId) noexcept
679 {
680     return coverException([&] {
681         IS_SET(id);
682         IS_SET(netdevId);
683
684         mClient->callSync<api::SetNetDevAttrsIn, api::Void>(
685             api::ipc::METHOD_SET_NETDEV_ATTRS,
686             std::make_shared<api::SetNetDevAttrsIn>(
687                 api::SetNetDevAttrsIn{ id, netdevId, { { "flags", to_string(IFF_UP) },
688                                                        { "change", to_string(IFF_UP) }  }  }));
689     });
690 }
691
692 VsmStatus Client::vsm_netdev_down(const char* id, const char* netdevId) noexcept
693 {
694     return coverException([&] {
695         IS_SET(id);
696         IS_SET(netdevId);
697
698         mClient->callSync<api::SetNetDevAttrsIn, api::Void>(
699             api::ipc::METHOD_SET_NETDEV_ATTRS,
700             std::make_shared<api::SetNetDevAttrsIn>(
701                 api::SetNetDevAttrsIn{ id, netdevId, { { "flags", to_string(~IFF_UP) },
702                                                        { "change", to_string(IFF_UP) }  }  }));
703     });
704 }
705
706 VsmStatus Client::vsm_create_netdev_veth(const char* id,
707                                     const char* zoneDev,
708                                     const char* hostDev) noexcept
709 {
710     return coverException([&] {
711         IS_SET(id);
712         IS_SET(zoneDev);
713         IS_SET(hostDev);
714
715         mClient->callSync<api::CreateNetDevVethIn, api::Void>(
716             api::ipc::METHOD_CREATE_NETDEV_VETH,
717             std::make_shared<api::CreateNetDevVethIn>(
718                 api::CreateNetDevVethIn{ id, zoneDev, hostDev }));
719     });
720 }
721
722 VsmStatus Client::vsm_create_netdev_macvlan(const char* id,
723                                        const char* zoneDev,
724                                        const char* hostDev,
725                                        enum macvlan_mode mode) noexcept
726 {
727     return coverException([&] {
728         IS_SET(id);
729         IS_SET(zoneDev);
730         IS_SET(hostDev);
731
732         mClient->callSync<api::CreateNetDevMacvlanIn, api::Void>(
733             api::ipc::METHOD_CREATE_NETDEV_MACVLAN,
734             std::make_shared<api::CreateNetDevMacvlanIn>(
735                 api::CreateNetDevMacvlanIn{ id, zoneDev, hostDev, mode }));
736     });
737 }
738
739 VsmStatus Client::vsm_create_netdev_phys(const char* id, const char* devId) noexcept
740 {
741     return coverException([&] {
742         IS_SET(id);
743         IS_SET(devId);
744
745         mClient->callSync<api::CreateNetDevPhysIn, api::Void>(
746             api::ipc::METHOD_CREATE_NETDEV_PHYS,
747             std::make_shared<api::CreateNetDevPhysIn>(
748                 api::CreateNetDevPhysIn{ id, devId }));
749     });
750 }
751
752 VsmStatus Client::vsm_lookup_netdev_by_name(const char* id,
753                                        const char* netdevId,
754                                        Netdev* netdev) noexcept
755 {
756     using namespace boost::algorithm;
757
758     return coverException([&] {
759         IS_SET(id);
760         IS_SET(netdevId);
761         IS_SET(netdev);
762
763         api::GetNetDevAttrs attrs = *mClient->callSync<api::GetNetDevAttrsIn, api::GetNetDevAttrs>(
764             api::ipc::METHOD_GET_NETDEV_ATTRS,
765             std::make_shared<api::GetNetDevAttrsIn>(api::GetNetDevAttrsIn{ id, netdevId }));
766         auto it = find_if(attrs.values.begin(),
767                           attrs.values.end(),
768                           [](const api::StringPair& entry) {
769                 return entry.first == "type";
770         });
771
772         VsmNetdevType type;
773         if (it == attrs.values.end()) {
774             throw OperationFailedException("Can't fetch netdev type");
775         }
776
777         switch (stoi(it->second)) {
778             case 1<<0  /*IFF_802_1Q_VLAN*/: type = VSMNETDEV_VETH; break;
779             case 1<<21 /*IFF_MACVLAN*/: type = VSMNETDEV_MACVLAN; break;
780             default:
781                 throw InvalidResponseException("Unknown netdev type: " + it->second);
782         }
783
784         *netdev = static_cast<Netdev>(malloc(sizeof(**netdev)));
785         (*netdev)->name = ::strdup(id);
786         (*netdev)->type = type;
787     });
788 }
789
790 VsmStatus Client::vsm_destroy_netdev(const char* id, const char* devId) noexcept
791 {
792     return coverException([&] {
793         IS_SET(id);
794         IS_SET(devId);
795
796         mClient->callSync<api::DestroyNetDevIn, api::Void>(
797             api::ipc::METHOD_DESTROY_NETDEV,
798             std::make_shared<api::DestroyNetDevIn>(api::DestroyNetDevIn{ id, devId }));
799     });
800 }
801
802 VsmStatus Client::vsm_declare_file(const char* id,
803                               VsmFileType type,
804                               const char *path,
805                               int32_t flags,
806                               mode_t mode,
807                               VsmString* declarationId) noexcept
808 {
809     return coverException([&] {
810         IS_SET(id);
811         IS_SET(path);
812
813         api::Declaration declaration = *mClient->callSync<api::DeclareFileIn, api::Declaration>(
814             api::ipc::METHOD_DECLARE_FILE,
815             std::make_shared<api::DeclareFileIn>(
816                 api::DeclareFileIn{ id, type, path, flags, (int)mode }));
817         if (declarationId != NULL) {
818             *declarationId = ::strdup(declaration.value.c_str());
819         }
820     });
821 }
822
823 VsmStatus Client::vsm_declare_mount(const char *source,
824                                const char* id,
825                                const char *target,
826                                const char *type,
827                                uint64_t flags,
828                                const char *data,
829                                VsmString* declarationId) noexcept
830 {
831     return coverException([&] {
832         IS_SET(source);
833         IS_SET(id);
834         IS_SET(target);
835         IS_SET(type);
836         if (!data) {
837             data = "";
838         }
839
840         api::Declaration declaration = *mClient->callSync<api::DeclareMountIn, api::Declaration>(
841             api::ipc::METHOD_DECLARE_MOUNT,
842             std::make_shared<api::DeclareMountIn>(
843                 api::DeclareMountIn{ source, id, target, type, flags, data }));
844         if (declarationId != NULL) {
845             *declarationId = ::strdup(declaration.value.c_str());
846         }
847     });
848 }
849
850 VsmStatus Client::vsm_declare_link(const char* source,
851                               const char* id,
852                               const char* target,
853                               VsmString* declarationId) noexcept
854 {
855     return coverException([&] {
856         IS_SET(source);
857         IS_SET(id);
858         IS_SET(target);
859
860         api::Declaration declaration = *mClient->callSync<api::DeclareLinkIn, api::Declaration>(
861             api::ipc::METHOD_DECLARE_LINK,
862             std::make_shared<api::DeclareLinkIn>(api::DeclareLinkIn{ source, id, target }));
863         if (declarationId != NULL) {
864             *declarationId = ::strdup(declaration.value.c_str());
865         }
866     });
867 }
868
869 VsmStatus Client::vsm_list_declarations(const char* id, VsmArrayString* declarations) noexcept
870 {
871     return coverException([&] {
872         IS_SET(id);
873         IS_SET(declarations);
874
875         api::Declarations declarationsOut = *mClient->callSync<api::ZoneId, api::Declarations>(
876             api::ipc::METHOD_GET_DECLARATIONS,
877             std::make_shared<api::ZoneId>(api::ZoneId{ id }));
878         convert(declarationsOut, *declarations);
879     });
880 }
881
882 VsmStatus Client::vsm_remove_declaration(const char* id, VsmString declaration) noexcept
883 {
884     return coverException([&] {
885         IS_SET(id);
886         IS_SET(declaration);
887
888         mClient->callSync<api::RemoveDeclarationIn, api::Void>(
889             api::ipc::METHOD_REMOVE_DECLARATION,
890             std::make_shared<api::RemoveDeclarationIn>(api::RemoveDeclarationIn{ id, declaration }));
891     });
892 }
893
894 VsmStatus Client::vsm_clean_up_zones_root() noexcept
895 {
896     return coverException([&] {
897         mClient->callSync<api::Void, api::Void>(
898             api::ipc::METHOD_CLEAN_UP_ZONES_ROOT,
899             std::make_shared<api::Void>());
900     });
901 }
902