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, VsmZone 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) {return v.zone->id == zone_name;};
307 auto zonelist = std::remove_if(w->zones.begin(), w->zones.end(), zonebyname);
308 w->zones.erase(zonelist);
310 return wrap_error(st, w->client);
313 API int vsm_start_zone(struct vsm_context *ctx, const char *zone_name)
315 LOGS("zone=" << zone_name);
317 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
318 if (!w->client) return VSM_ERROR_GENERIC;
319 VsmStatus st = w->client->vsm_start_zone(zone_name);
320 return wrap_error(st, w->client);
323 API int vsm_shutdown_zone(struct vsm_context *ctx, const char *zone_name, int force)
325 LOGS("zone=" << zone_name);
327 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
329 if (!w->client) return VSM_ERROR_GENERIC;
330 VsmStatus st = w->client->vsm_shutdown_zone(zone_name);
331 return wrap_error(st, w->client);
334 API int vsm_lock_zone(struct vsm_context *ctx, const char *zone_name, int shutdown)
336 LOGS("zone=" << zone_name);
338 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
340 if (!w->client) return VSM_ERROR_GENERIC;
341 VsmStatus st = w->client->vsm_lock_zone(zone_name);
342 return wrap_error(st, w->client);
345 API int vsm_unlock_zone(struct vsm_context *ctx, const char *zone_name)
347 LOGS("zone=" << zone_name);
349 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
350 if (!w->client) return VSM_ERROR_GENERIC;
351 VsmStatus st = w->client->vsm_lock_zone(zone_name);
352 return wrap_error(st, w->client);
355 API int vsm_set_foreground(struct vsm_zone *zone)
359 WrappedZone *w = container_of(zone, WrappedZone, vz);
360 if (!w->client) return VSM_ERROR_GENERIC;
361 VsmStatus st = w->client->vsm_set_active_zone(zone->name);
362 return wrap_error(st, w->client);
365 //execute command in specified zone
366 API int vsm_attach_zone(struct vsm_context *ctx,
367 const char *zone_name,
368 vsm_attach_command_t *command,
369 vsm_attach_options_t *opts,
370 pid_t *attached_process)
372 return dummy_ops.attach_zone(ctx, zone_name, command, opts,
376 //execute command in specified zone and wait
377 API int vsm_attach_zone_wait(struct vsm_context *ctx,
378 const char *zone_name,
379 vsm_attach_command_t *command,
380 vsm_attach_options_t *opts)
382 return dummy_ops.attach_zone_wait(ctx, zone_name, command, opts);
385 API int vsm_iterate_zone(struct vsm_context *ctx, void (*callback)(struct vsm_zone *zone, void *user_data), void *user_data)
389 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
390 if (!w->client) return -VSM_ERROR_GENERIC;
391 callback(ctx->root_zone, user_data);
392 for (auto& z : w->zones) {
393 LOGI("iterate callback zone: " << z.zone->id);
394 callback(&z.vz, user_data);
399 API struct vsm_zone *vsm_lookup_zone_by_name(struct vsm_context *ctx, const char *path)
401 LOGS("name=" << path);
403 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
405 if (!w->client) return NULL;
406 //CHECK if path is same as zone_name
407 if (w->client->vsm_lookup_zone_by_id(path, &zone) != VSMCLIENT_SUCCESS)
409 return wrap_vsm_zone(w, zone, true);
412 //supposed return ref to internal struct
413 API struct vsm_zone *vsm_lookup_zone_by_pid(struct vsm_context *ctx, pid_t pid)
417 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
421 if (!w->client) return NULL;
422 if ((st = w->client->vsm_lookup_zone_by_pid(pid, &id)) != VSMCLIENT_SUCCESS) {
423 wrap_error(st, w->client);
426 LOGI("found zone(pid=" << pid << ")='" << id << "'");
427 if (::strcmp(id, "host") == 0) {
428 return w->hq_ctx.root_zone;
430 w->client->vsm_lookup_zone_by_id(id, &zone); //zone is malloced
431 return wrap_vsm_zone(w, zone);
434 API int vsm_add_state_changed_callback(struct vsm_context *ctx, vsm_zone_state_changed_cb callback, void *user_data)
438 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
439 VsmSubscriptionId subscriptionId;
441 auto dbus_cb = [=](const char* id, const char* dbusAddress, void* data) ->
444 //TODO what are valid state, event
445 vsm_zone_state_t t = VSM_ZONE_STATE_RUNNING;
447 w->client->vsm_lookup_zone_by_id(id, &zone);
448 callback(wrap_vsm_zone(w, zone), t, data);
450 w->client->vsm_add_state_callback(dbus_cb, user_data, &subscriptionId);
451 return (int)subscriptionId;
454 API int vsm_del_state_changed_callback(struct vsm_context *ctx, int handle)
458 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
459 VsmSubscriptionId subscriptionId = (VsmSubscriptionId)handle;
460 VsmStatus st = w->client->vsm_del_state_callback(subscriptionId);
461 return wrap_error(st, w->client);
464 API int vsm_grant_device(struct vsm_zone *dom, const char *name, uint32_t flags)
468 WrappedZone *w = container_of(dom, WrappedZone, vz);
469 const char *id = dom->name;
471 w->client->vsm_lookup_zone_by_id(id, &zone);
472 VsmStatus st = w->client->vsm_grant_device(id, name, flags);
473 return wrap_error(st, w->client);
476 API int vsm_revoke_device(struct vsm_zone *dom, const char *name)
480 WrappedZone *w = container_of(dom, WrappedZone, vz);
481 const char *id = dom->name;
482 VsmStatus st = w->client->vsm_revoke_device(id, name);
483 return wrap_error(st, w->client);
486 API struct vsm_netdev *vsm_create_netdev(struct vsm_zone *zone, vsm_netdev_type_t type, const char *target, const char *netdev)
495 WrappedZone *w = container_of(zone, WrappedZone, vz);
496 const char *id = zone->name;
498 if (type == VSM_NETDEV_VETH)
499 st = w->client->vsm_create_netdev_veth(id, target, netdev);
500 else if (type == VSM_NETDEV_PHYS)
501 st = w->client->vsm_create_netdev_phys(id, netdev);
502 else if (type == VSM_NETDEV_MACVLAN) // macvlan_mode from if_link.h
503 st = w->client->vsm_create_netdev_macvlan(id, target, netdev, MACVLAN_MODE_BRIDGE);
505 LOGE("Invalid arguments");
506 //ctx->error = VSM_ERROR_INVALID;
510 if (st != VSMCLIENT_SUCCESS) {
511 LOGE("vsm_create_netdev(" << netdev << ") = " << st);
517 vnd.name = (char*)netdev; //FIXME? copy content of string
519 w->netdevs.push_back(vnd); //copy pushed to vector
520 return &w->netdevs.back(); //pointer to struct on vector
523 API int vsm_destroy_netdev(vsm_netdev_h)
529 API int vsm_iterate_netdev(struct vsm_zone *zone, void (*callback)(struct vsm_netdev *, void *user_data), void *user_data)
533 WrappedZone *w = container_of(zone, WrappedZone, vz);
534 for (auto nd : w->netdevs) {
535 callback(&nd, user_data);
540 API struct vsm_netdev *vsm_lookup_netdev_by_name(struct vsm_zone *zone, const char *name)
544 WrappedZone *w = container_of(zone, WrappedZone, vz);
546 VsmStatus st = w->client->vsm_lookup_netdev_by_name(zone->name, name, &nd);
547 if (st == VSMCLIENT_SUCCESS) {
548 auto devbyname = [name](const vsm_netdev& v) {return ::strcmp(v.name, name) == 0;};
549 auto devlist = std::find_if(w->netdevs.begin(), w->netdevs.end(), devbyname);
550 if (devlist != w->netdevs.end()) {
557 API int vsm_declare_file(struct vsm_context *ctx, vsm_fso_type_t ftype, const char *path, int flags, vsm_mode_t mode)
561 /* Old implementation is following: (but implemented in server)
562 args.oldpath = oldpath;
563 args.newpath = newpath;
564 ret = iterate_running_zone("/sys/fs/cgroup/cpuset/lxc", file_resource, &args);
566 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
567 VsmArrayString ids = NULL;
570 case VSM_FSO_TYPE_DIR: /**< Directoy type */
571 type = VSMFILE_DIRECTORY;
573 case VSM_FSO_TYPE_REG: /**< Regular file type */
574 type = VSMFILE_REGULAR;
576 case VSM_FSO_TYPE_FIFO: /**< Fifo file type */
579 case VSM_FSO_TYPE_SOCK: /**< Socket file type */
580 return VSM_ERROR_NONE;
581 case VSM_FSO_TYPE_DEV: /**< Device node type */
582 return VSM_ERROR_NONE;
584 return VSM_ERROR_NONE;
586 w->client->vsm_get_zone_ids(&ids);
588 for (VsmString* id = ids; *id; ++id) {
589 VsmStatus st = w->client->vsm_declare_file(*id, type, path, (int32_t)flags, (mode_t)mode, NULL);
590 if (st != VSMCLIENT_SUCCESS) {
591 wrap_error(st, w->client);
595 vsm_array_string_free(ids);
596 return VSM_ERROR_NONE;
599 API int vsm_declare_link(struct vsm_context *ctx, const char *source, const char *target)
601 LOGS("src=" << source << ", dst=" << target);
603 /* Old implementation is following: (but implemented in server)
604 args.oldpath = oldpath;
605 args.newpath = newpath;
606 ret = iterate_running_zone("/sys/fs/cgroup/cpuset/lxc", link_resource, &args);
608 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
609 VsmArrayString ids = NULL;
610 w->client->vsm_get_zone_ids(&ids);
612 for (VsmString* id = ids; *id; ++id) {
613 VsmStatus st = w->client->vsm_declare_link(source, *id, target, NULL);
614 if (st != VSMCLIENT_SUCCESS)
615 wrap_error(st, w->client);
617 vsm_array_string_free(ids);
618 return VSM_ERROR_NONE;
621 API int vsm_declare_mount(struct vsm_context *ctx,
630 /* Old implementation is following: (but implemented in server)
631 args.oldpath = oldpath;
632 args.newpath = newpath;
633 ret = iterate_running_zone("/sys/fs/cgroup/cpuset/lxc", mount_resource, &args);
635 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
636 VsmArrayString ids = NULL;
637 w->client->vsm_get_zone_ids(&ids);
639 for (VsmString* id = ids; *id; ++id) {
640 VsmStatus st = w->client->vsm_declare_mount(source, *id, target, fstype, flags, (const char *)data, NULL);
641 if (st != VSMCLIENT_SUCCESS) {
642 wrap_error(st, w->client);
646 vsm_array_string_free(ids);
647 return VSM_ERROR_NONE;
650 API const char * vsm_get_zone_rootpath(vsm_zone_h zone)
653 return zone == NULL ? NULL : zone->rootfs_path;
655 API const char * vsm_get_zone_name(vsm_zone_h zone)
658 return zone == NULL ? NULL : zone->name;
660 API int vsm_is_host_zone(vsm_zone_h zone)
664 return -VSM_ERROR_INVALID;
666 LOGI("zone->parent == zone is " << (zone->parent == zone ? 1 : 0));
667 return zone->parent == zone ? 1 : 0;
669 API vsm_zone_h vsm_join_zone(vsm_zone_h /*zone*/)
674 API int vsm_canonicalize_path(const char *input_path, char **output_path)
676 LOGS(""<<input_path);
677 *output_path = strdup(input_path);
678 int len = strlen(input_path);
682 // Note: support the newer API (incomaptible with older)
683 API const char *vsm_error_string(vsm_error_e error)
687 if (error < 0 || error > VSM_MAX_ERROR) {
690 return vsm_error_strtab[error];
693 API struct vsm_zone *vsm_lookup_zone_by_terminal_id(struct vsm_context *ctx, int terminal)
695 LOGS("terminal=" << terminal);
697 WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
700 if (!w->client) return NULL;
701 if (w->client->vsm_lookup_zone_by_terminal_id(terminal, &id) != VSMCLIENT_SUCCESS)
703 w->client->vsm_lookup_zone_by_id(id, &zone);
704 return wrap_vsm_zone(w, zone);
707 API void vsm_array_string_free(VsmArrayString astring)
712 for (char** ptr = astring; *ptr; ++ptr) {
713 vsm_string_free(*ptr);
718 API void vsm_string_free(VsmString string)
723 API int vsm_add_event_callback(vsm_context_h, vsm_zone_event_cb, void*) {
727 API int vsm_del_event_callback(vsm_context_h, int) {
731 API int vsm_add_state_callback(vsm_context_h , vsm_zone_state_cb , void *) {
735 API int vsm_del_state_callback(vsm_context_h , int ) {
739 API int vsm_down_netdev(vsm_netdev_h) {
743 API vsm_zone* vsm_get_foreground(vsm_context_h ctx) {
745 //return ((struct vasum_ops *)(ctx->vsm_ops))->get_foreground(ctx);
746 return dummy_ops.get_foreground(ctx);
748 API int vsm_get_host_pid(vsm_zone_h, pid_t) {
752 API int vsm_get_ip_addr_netdev(vsm_netdev_h, vsm_netdev_addr_t, char*, int) {
756 API void* vsm_get_userdata(vsm_zone_h) {
760 API int vsm_get_zone_id(vsm_zone_h zone) {
763 return -VSM_ERROR_INVALID;
766 API vsm_zone_state_t vsm_get_zone_state(vsm_zone_h zone) {
769 return static_cast<vsm_zone_state_t>(-VSM_ERROR_INVALID);
772 API int vsm_get_zone_terminal(vsm_zone_h) {
774 return -VSM_ERROR_NOT_SUPPORTED;
776 API const char *vsm_get_zone_type(vsm_zone_h zone) {
778 return zone == NULL ? NULL : zone->type;
780 API int vsm_is_equivalent_zone(vsm_context_h, pid_t) {
784 API int vsm_is_virtualized() {
786 return 0; /* Running in Host */
789 API int vsm_set_ip_addr_netdev(vsm_netdev_h, vsm_netdev_addr_t, const char*, int) {
793 API int vsm_up_netdev(vsm_netdev_h) {
798 API int vsm_set_userdata(vsm_zone_h, void*) {
802 API int vsm_state_change_watch_callback(struct vsm_context * /*ctx*/, char * /*name*/,
803 int /*state*/, int /*event*/) {
808 API int vsm_signal_state_broadcast(struct mxe_engine * /*engine*/, const char * /*zone_name*/, int /*state*/) {
812 API int vsm_signal_event_broadcast(struct mxe_engine * /*engine*/, const char * /*zone_name*/, int /*event*/) {