2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Krzysztof Dynowski <k.dynowski@samsung.com>
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
22 * @author Krzysztof Dynowski (k.dynowski@samsung.com)
23 * @brief Vasum old API wrapper to slp client lib
26 #define __VASUM_WRAPPER_SOURCE__
32 #include "vasum-client-impl.hpp"
33 #include "logger/logger.hpp"
34 #include "logger/backend-journal.hpp"
36 #include "wrapper-compatibility.h"
43 std::vector<vsm_netdev> netdevs;
50 struct vsm_zone hq_root;
51 std::vector<WrappedZone> zones;
61 #define offsetof(type, memb) ((size_t)&((type *)0)->memb)
67 #define container_of(ptr, type, memb) (\
68 (type *)((char *)(ptr) - offsetof(type, memb)))
71 #define UNUSED(x) ((void)(x))
73 #define vsm_attach_command_t vsm_attach_command_s
74 #define vsm_attach_options_t vsm_attach_options_s
76 void __attribute__ ((constructor)) wrapper_load(void);
77 void __attribute__ ((destructor)) wrapper_unload(void);
78 static void init_wrapper();
79 extern struct vasum_ops dummy_ops;
81 using namespace logger;
82 void wrapper_load(void)
84 Logger::setLogLevel(LogLevel::TRACE);
85 Logger::setLogBackend(new SystemdJournalBackend());
90 void wrapper_unload(void)
92 LOGI("wrapper_unload");
95 static void callcheck()
102 if (wrap.done) return ;
103 memset(&wrap, 0, sizeof(wrap));
108 static struct vsm_zone* wrap_vsm_zone(WrappedContext *w, Zone zone, bool create = false)
113 for (auto& zw : w->zones) {
114 if (zw.zone == zone) {
119 w->zones.push_back(WrappedZone());
120 WrappedZone& zw = w->zones.back();
121 zw.client = w->client;
123 zw.vz.name = zone->id;
126 zw.vz.user_data = NULL;
127 zw.vz.rootfs_path = zone->rootfs_path;
128 zw.vz.parent = &zw.vz;
129 LOGI("return (create) zone " << zone->id);
130 return &w->zones.back().vz;
132 LOGE("return zone NULL");
136 static int wrap_error(VsmStatus st, const Client *c)
138 if (st == VSMCLIENT_SUCCESS) LOGI("return success " << st);
139 else LOGE("return error=" << st << ", msg=" << (c ? c->vsm_get_status_message() : "n/a"));
141 case VSMCLIENT_SUCCESS: return VSM_ERROR_NONE;
142 case VSMCLIENT_CUSTOM_ERROR: return -VSM_ERROR_GENERIC;
143 case VSMCLIENT_IO_ERROR: return -VSM_ERROR_IO;
144 case VSMCLIENT_OPERATION_FAILED: return -VSM_ERROR_NOT_PERMITTED;
145 case VSMCLIENT_INVALID_ARGUMENT: return -VSM_ERROR_INVALID;
146 case VSMCLIENT_OTHER_ERROR: return -VSM_ERROR_GENERIC;
148 return -VSM_ERROR_GENERIC;
151 static void init_context_wrap(WrappedContext *w)
153 w->client = new Client();
154 VsmStatus st = w->client->connectSystem();
155 wrap_error(st, w->client);
157 memset(&w->hq_ctx, 0, sizeof(w->hq_ctx));
158 memset(&w->hq_root, 0, sizeof(w->hq_root));
160 vsm_context *ctx = &w->hq_ctx;
161 adt_init_list(&ctx->listeners);
163 ctx->root_zone = &w->hq_root;
164 ctx->root_zone->name = (char*)"";
165 ctx->root_zone->id = 0;
166 ctx->root_zone->rootfs_path = (char*)"/";
168 ctx->root_zone->terminal = -1;
169 ctx->root_zone->state = VSM_ZONE_STATE_RUNNING;
170 ctx->root_zone->user_data = ctx->root_zone;
172 ctx->root_zone->parent = ctx->root_zone;
173 ctx->root_zone->ctx = ctx;
175 pthread_rwlock_init(&ctx->root_zone->lock, NULL);
176 adt_init_list(&ctx->root_zone->netdevs);
177 adt_init_list(&ctx->root_zone->devices);
178 adt_init_list(&ctx->root_zone->children);
180 pthread_rwlock_init(&ctx->lock, NULL);
181 adt_init_list(&ctx->listeners);
182 adt_init_list(&ctx->sc_listeners);
183 adt_init_list(&ctx->ev_listeners);
185 //struct mainloop *mainloop = mainloop_create();
186 //struct mxe_engine *engine = mxe_prepare_engine(mainloop, ctx);
187 //struct mxe_endpoint *ep = mxe_create_client(engine, SERVICEPATH);
189 ctx->foreground_zone = ctx->root_zone;
190 ctx->vsm_ops = &dummy_ops;
191 ctx->error = VSM_ERROR_NONE;
196 API void vsm_string_free(VsmString string);
197 API void vsm_array_string_free(VsmArrayString astring);
199 API vsm_context_h vsm_create_context(void)
203 WrappedContext *w = new WrappedContext();
204 init_context_wrap(w);
206 vsm_context *ctx = &w->hq_ctx;
210 API int vsm_cleanup_context(vsm_context_h ctx)
214 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
215 if (w->client != NULL) {
219 for (auto& zw : w->zones) {
223 pthread_rwlock_destroy(&ctx->lock);
225 return VSM_ERROR_NONE;
228 static const char *const vsm_error_strtab[] = {
232 "Operation cancelled",
234 "Connection refused",
237 "Input/Output error",
242 "Operation not permitted",
243 "Function not implemented",
244 "Operation not supported",
250 API vsm_error_e vsm_last_error(struct vsm_context *ctx)
254 return static_cast<vsm_error_e>(-1);
257 API int vsm_get_poll_fd(struct vsm_context *ctx)
261 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
263 //FIXME Client should create Dispatcher and pass to IPCConnection
264 // now: IPCConnection has field ThreadWrapper
265 //return w->client->getEventPoll().getPollFD();
268 API int vsm_enter_eventloop(struct vsm_context *ctx, int flags, int timeout)
274 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
276 //FIXME Client should create Dispatcher and pass to IPCConnection
277 // now: IPCConnection has field ThreadWrapper
278 //TODO Use EventPoll from Dispatcher
282 API int vsm_create_zone(struct vsm_context *ctx, const char *zone_name, const char *template_name, int flag)
284 LOGS("create_zone " << zone_name);
286 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
288 //template_name = NULL; //template name not supported by libvasum-client
289 if (!w->client) return VSM_ERROR_GENERIC;
290 VsmStatus st = w->client->vsm_create_zone(zone_name, template_name);
291 if (st != VSMCLIENT_SUCCESS) {
292 LOGE("vsm_create_zone(" << zone_name << ") = " << st);
294 return wrap_error(st, w->client);
297 API int vsm_destroy_zone(struct vsm_context *ctx, const char *zone_name, int force)
299 LOGS("zone=" << zone_name);
301 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
303 if (!w->client) return VSM_ERROR_GENERIC;
304 VsmStatus st = w->client->vsm_destroy_zone(zone_name);
305 if (st == VSMCLIENT_SUCCESS) {
306 auto zonebyname = [zone_name](const WrappedZone& v) {
307 return static_cast<Zone>(v.zone)->id == zone_name;
309 auto zonelist = std::remove_if(w->zones.begin(), w->zones.end(), zonebyname);
310 w->zones.erase(zonelist);
312 return wrap_error(st, w->client);
315 API int vsm_start_zone(struct vsm_context *ctx, const char *zone_name)
317 LOGS("zone=" << zone_name);
319 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
320 if (!w->client) return VSM_ERROR_GENERIC;
321 VsmStatus st = w->client->vsm_start_zone(zone_name);
322 return wrap_error(st, w->client);
325 API int vsm_shutdown_zone(struct vsm_context *ctx, const char *zone_name, int force)
327 LOGS("zone=" << zone_name);
329 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
331 if (!w->client) return VSM_ERROR_GENERIC;
332 VsmStatus st = w->client->vsm_shutdown_zone(zone_name);
333 return wrap_error(st, w->client);
336 API int vsm_lock_zone(struct vsm_context *ctx, const char *zone_name, int shutdown)
338 LOGS("zone=" << zone_name);
340 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
342 if (!w->client) return VSM_ERROR_GENERIC;
343 VsmStatus st = w->client->vsm_lock_zone(zone_name);
344 return wrap_error(st, w->client);
347 API int vsm_unlock_zone(struct vsm_context *ctx, const char *zone_name)
349 LOGS("zone=" << zone_name);
351 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
352 if (!w->client) return VSM_ERROR_GENERIC;
353 VsmStatus st = w->client->vsm_lock_zone(zone_name);
354 return wrap_error(st, w->client);
357 API int vsm_set_foreground(struct vsm_zone *zone)
361 WrappedZone *w = container_of(zone, WrappedZone, vz);
362 if (!w->client) return VSM_ERROR_GENERIC;
363 VsmStatus st = w->client->vsm_set_active_zone(zone->name);
364 return wrap_error(st, w->client);
367 //execute command in specified zone
368 API int vsm_attach_zone(struct vsm_context *ctx,
369 const char *zone_name,
370 vsm_attach_command_t *command,
371 vsm_attach_options_t *opts,
372 pid_t *attached_process)
374 return dummy_ops.attach_zone(ctx, zone_name, command, opts,
378 //execute command in specified zone and wait
379 API int vsm_attach_zone_wait(struct vsm_context *ctx,
380 const char *zone_name,
381 vsm_attach_command_t *command,
382 vsm_attach_options_t *opts)
384 return dummy_ops.attach_zone_wait(ctx, zone_name, command, opts);
387 API int vsm_iterate_zone(struct vsm_context *ctx, void (*callback)(struct vsm_zone *zone, void *user_data), void *user_data)
391 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
392 if (!w->client) return -VSM_ERROR_GENERIC;
393 callback(ctx->root_zone, user_data);
394 for (auto& z : w->zones) {
395 LOGI("iterate callback zone: " << static_cast<Zone>(z.zone)->id);
396 callback(&z.vz, user_data);
401 API struct vsm_zone *vsm_lookup_zone_by_name(struct vsm_context *ctx, const char *path)
403 LOGS("name=" << path);
405 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
407 if (!w->client) return NULL;
408 //CHECK if path is same as zone_name
409 if (w->client->vsm_lookup_zone_by_id(path, &zone) != VSMCLIENT_SUCCESS)
411 return wrap_vsm_zone(w, zone, true);
414 //supposed return ref to internal struct
415 API struct vsm_zone *vsm_lookup_zone_by_pid(struct vsm_context *ctx, pid_t pid)
419 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
423 if (!w->client) return NULL;
424 if ((st = w->client->vsm_lookup_zone_by_pid(pid, &id)) != VSMCLIENT_SUCCESS) {
425 wrap_error(st, w->client);
428 LOGI("found zone(pid=" << pid << ")='" << id << "'");
429 if (::strcmp(id, "host") == 0) {
430 return w->hq_ctx.root_zone;
432 w->client->vsm_lookup_zone_by_id(id, &zone); //zone is malloced
433 return wrap_vsm_zone(w, zone);
436 API int vsm_add_state_changed_callback(struct vsm_context *ctx, vsm_zone_state_changed_cb callback, void *user_data)
440 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
441 VsmSubscriptionId subscriptionId;
443 auto dbus_cb = [=](const char* id, const char* dbusAddress, void* data) ->
446 //TODO what are valid state, event
447 vsm_zone_state_t t = VSM_ZONE_STATE_RUNNING;
449 w->client->vsm_lookup_zone_by_id(id, &zone);
450 callback(wrap_vsm_zone(w, zone), t, data);
452 w->client->vsm_add_state_callback(dbus_cb, user_data, &subscriptionId);
453 return (int)subscriptionId;
456 API int vsm_del_state_changed_callback(struct vsm_context *ctx, int handle)
460 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
461 VsmSubscriptionId subscriptionId = (VsmSubscriptionId)handle;
462 VsmStatus st = w->client->vsm_del_state_callback(subscriptionId);
463 return wrap_error(st, w->client);
466 API int vsm_grant_device(struct vsm_zone *dom, const char *name, uint32_t flags)
470 WrappedZone *w = container_of(dom, WrappedZone, vz);
471 const char *id = dom->name;
473 w->client->vsm_lookup_zone_by_id(id, &zone);
474 VsmStatus st = w->client->vsm_grant_device(id, name, flags);
475 return wrap_error(st, w->client);
478 API int vsm_revoke_device(struct vsm_zone *dom, const char *name)
482 WrappedZone *w = container_of(dom, WrappedZone, vz);
483 const char *id = dom->name;
484 VsmStatus st = w->client->vsm_revoke_device(id, name);
485 return wrap_error(st, w->client);
488 API struct vsm_netdev *vsm_create_netdev(struct vsm_zone *zone, vsm_netdev_type_t type, const char *target, const char *netdev)
497 WrappedZone *w = container_of(zone, WrappedZone, vz);
498 const char *id = zone->name;
500 if (type == VSM_NETDEV_VETH)
501 st = w->client->vsm_create_netdev_veth(id, target, netdev);
502 else if (type == VSM_NETDEV_PHYS)
503 st = w->client->vsm_create_netdev_phys(id, netdev);
504 else if (type == VSM_NETDEV_MACVLAN) // macvlan_mode from if_link.h
505 st = w->client->vsm_create_netdev_macvlan(id, target, netdev, MACVLAN_MODE_BRIDGE);
507 LOGE("Invalid arguments");
508 //ctx->error = VSM_ERROR_INVALID;
512 if (st != VSMCLIENT_SUCCESS) {
513 LOGE("vsm_create_netdev(" << netdev << ") = " << st);
519 vnd.name = (char*)netdev; //FIXME? copy content of string
521 w->netdevs.push_back(vnd); //copy pushed to vector
522 return &w->netdevs.back(); //pointer to struct on vector
525 API int vsm_destroy_netdev(vsm_netdev_h)
531 API int vsm_iterate_netdev(struct vsm_zone *zone, void (*callback)(struct vsm_netdev *, void *user_data), void *user_data)
535 WrappedZone *w = container_of(zone, WrappedZone, vz);
536 for (auto nd : w->netdevs) {
537 callback(&nd, user_data);
542 API struct vsm_netdev *vsm_lookup_netdev_by_name(struct vsm_zone *zone, const char *name)
546 WrappedZone *w = container_of(zone, WrappedZone, vz);
548 VsmStatus st = w->client->vsm_lookup_netdev_by_name(zone->name, name, &nd);
549 if (st == VSMCLIENT_SUCCESS) {
550 auto devbyname = [name](const vsm_netdev& v) {return ::strcmp(v.name, name) == 0;};
551 auto devlist = std::find_if(w->netdevs.begin(), w->netdevs.end(), devbyname);
552 if (devlist != w->netdevs.end()) {
559 API int vsm_declare_file(struct vsm_context *ctx, vsm_fso_type_t ftype, const char *path, int flags, vsm_mode_t mode)
563 /* Old implementation is following: (but implemented in server)
564 args.oldpath = oldpath;
565 args.newpath = newpath;
566 ret = iterate_running_zone("/sys/fs/cgroup/cpuset/lxc", file_resource, &args);
568 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
569 VsmArrayString ids = NULL;
572 case VSM_FSO_TYPE_DIR: /**< Directoy type */
573 type = VSMFILE_DIRECTORY;
575 case VSM_FSO_TYPE_REG: /**< Regular file type */
576 type = VSMFILE_REGULAR;
578 case VSM_FSO_TYPE_FIFO: /**< Fifo file type */
581 case VSM_FSO_TYPE_SOCK: /**< Socket file type */
582 return VSM_ERROR_NONE;
583 case VSM_FSO_TYPE_DEV: /**< Device node type */
584 return VSM_ERROR_NONE;
586 return VSM_ERROR_NONE;
588 w->client->vsm_get_zone_ids(&ids);
590 for (VsmString* id = ids; *id; ++id) {
591 VsmStatus st = w->client->vsm_declare_file(*id, type, path, (int32_t)flags, (mode_t)mode, NULL);
592 if (st != VSMCLIENT_SUCCESS) {
593 wrap_error(st, w->client);
597 vsm_array_string_free(ids);
598 return VSM_ERROR_NONE;
601 API int vsm_declare_link(struct vsm_context *ctx, const char *source, const char *target)
603 LOGS("src=" << source << ", dst=" << target);
605 /* Old implementation is following: (but implemented in server)
606 args.oldpath = oldpath;
607 args.newpath = newpath;
608 ret = iterate_running_zone("/sys/fs/cgroup/cpuset/lxc", link_resource, &args);
610 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
611 VsmArrayString ids = NULL;
612 w->client->vsm_get_zone_ids(&ids);
614 for (VsmString* id = ids; *id; ++id) {
615 VsmStatus st = w->client->vsm_declare_link(source, *id, target, NULL);
616 if (st != VSMCLIENT_SUCCESS)
617 wrap_error(st, w->client);
619 vsm_array_string_free(ids);
620 return VSM_ERROR_NONE;
623 API int vsm_declare_mount(struct vsm_context *ctx,
632 /* Old implementation is following: (but implemented in server)
633 args.oldpath = oldpath;
634 args.newpath = newpath;
635 ret = iterate_running_zone("/sys/fs/cgroup/cpuset/lxc", mount_resource, &args);
637 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
638 VsmArrayString ids = NULL;
639 w->client->vsm_get_zone_ids(&ids);
641 for (VsmString* id = ids; *id; ++id) {
642 VsmStatus st = w->client->vsm_declare_mount(source, *id, target, fstype, flags, (const char *)data, NULL);
643 if (st != VSMCLIENT_SUCCESS) {
644 wrap_error(st, w->client);
648 vsm_array_string_free(ids);
649 return VSM_ERROR_NONE;
652 API const char * vsm_get_zone_rootpath(vsm_zone_h zone)
655 return zone == NULL ? NULL : zone->rootfs_path;
657 API const char * vsm_get_zone_name(vsm_zone_h zone)
660 return zone == NULL ? NULL : zone->name;
662 API int vsm_is_host_zone(vsm_zone_h zone)
666 return -VSM_ERROR_INVALID;
668 LOGI("zone->parent == zone is " << (zone->parent == zone ? 1 : 0));
669 return zone->parent == zone ? 1 : 0;
671 API vsm_zone_h vsm_join_zone(vsm_zone_h /*zone*/)
676 API int vsm_canonicalize_path(const char *input_path, char **output_path)
678 LOGS(""<<input_path);
679 *output_path = strdup(input_path);
680 int len = strlen(input_path);
684 // Note: support the newer API (incomaptible with older)
685 API const char *vsm_error_string(vsm_error_e error)
689 if (error < 0 || error > VSM_MAX_ERROR) {
692 return vsm_error_strtab[error];
695 API struct vsm_zone *vsm_lookup_zone_by_terminal_id(struct vsm_context *ctx, int terminal)
697 LOGS("terminal=" << terminal);
699 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
702 if (!w->client) return NULL;
703 if (w->client->vsm_lookup_zone_by_terminal_id(terminal, &id) != VSMCLIENT_SUCCESS)
705 w->client->vsm_lookup_zone_by_id(id, &zone);
706 return wrap_vsm_zone(w, zone);
709 API void vsm_array_string_free(VsmArrayString astring)
714 for (char** ptr = astring; *ptr; ++ptr) {
715 vsm_string_free(*ptr);
720 API void vsm_string_free(VsmString string)
725 API int vsm_add_event_callback(vsm_context_h, vsm_zone_event_cb, void*) {
729 API int vsm_del_event_callback(vsm_context_h, int) {
733 API int vsm_add_state_callback(vsm_context_h , vsm_zone_state_cb , void *) {
737 API int vsm_del_state_callback(vsm_context_h , int ) {
741 API int vsm_down_netdev(vsm_netdev_h) {
745 API vsm_zone* vsm_get_foreground(vsm_context_h ctx) {
747 //return ((struct vasum_ops *)(ctx->vsm_ops))->get_foreground(ctx);
748 return dummy_ops.get_foreground(ctx);
750 API int vsm_get_host_pid(vsm_zone_h, pid_t) {
754 API int vsm_get_ip_addr_netdev(vsm_netdev_h, vsm_netdev_addr_t, char*, int) {
758 API void* vsm_get_userdata(vsm_zone_h) {
762 API int vsm_get_zone_id(vsm_zone_h zone) {
765 return -VSM_ERROR_INVALID;
768 API vsm_zone_state_t vsm_get_zone_state(vsm_zone_h zone) {
771 return static_cast<vsm_zone_state_t>(-VSM_ERROR_INVALID);
774 API int vsm_get_zone_terminal(vsm_zone_h) {
776 return -VSM_ERROR_NOT_SUPPORTED;
778 API const char *vsm_get_zone_type(vsm_zone_h zone) {
780 return zone == NULL ? NULL : zone->type;
782 API int vsm_is_equivalent_zone(vsm_context_h, pid_t) {
786 API int vsm_is_virtualized() {
788 return 0; /* Running in Host */
791 API int vsm_set_ip_addr_netdev(vsm_netdev_h, vsm_netdev_addr_t, const char*, int) {
795 API int vsm_up_netdev(vsm_netdev_h) {
800 API int vsm_set_userdata(vsm_zone_h, void*) {
804 API int vsm_state_change_watch_callback(struct vsm_context * /*ctx*/, char * /*name*/,
805 int /*state*/, int /*event*/) {
810 API int vsm_signal_state_broadcast(struct mxe_engine * /*engine*/, const char * /*zone_name*/, int /*state*/) {
814 API int vsm_signal_event_broadcast(struct mxe_engine * /*engine*/, const char * /*zone_name*/, int /*event*/) {