GCC Code Coverage Report


Directory: src/gate/
File: src/gate/tech/virtualization.c
Date: 2026-05-04 21:11:01
Exec Total Coverage
Lines: 18 208 8.7%
Functions: 3 27 11.1%
Branches: 6 86 7.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2026, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/tech/virtualization.h"
30
31 #include "gate/results.h"
32
33
34 static gate_string_t const virtprov_name_lxc = GATE_STRING_INIT_STATIC("lxc");
35 static gate_string_t const virtprov_descr_lxc = GATE_STRING_INIT_STATIC("Linux-Containers");
36
37 static gate_string_t const virtprov_name_docker = GATE_STRING_INIT_STATIC("docker");
38 static gate_string_t const virtprov_descr_docker = GATE_STRING_INIT_STATIC("Docker");
39
40 #if defined(GATE_SYS_LINUX)
41 # define GATE_TECH_VIRTUALIZATION_LXC 1
42 #endif
43
44 #if defined(GATE_SYS_WIN) && !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WIN16)
45 # define GATE_TECH_VIRTUALIZATION_HYPERV2 1
46 # define GATE_TECH_VIRTUALIZATION_WSL 1
47 #endif
48
49 #define GATE_TECH_VIRTUALIZATION_DOCKER 1
50
51
52
53
54 #if defined(GATE_TECH_VIRTUALIZATION_LXC)
55
56 #include <stdlib.h>
57
58 #include "gate/tech/platform/gate_lxc.h"
59 #include "gate/utilities.h"
60 #include "gate/debugging.h"
61
62 static gate_lxc_functions_t lxc_code;
63 static gate_bool_t lxc_code_init;
64
65 1 static gate_result_t gate_lxc_init()
66 {
67 1 gate_result_t ret = GATE_RESULT_OK;
68
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!lxc_code_init)
69 {
70 1 ret = gate_load_lxc_functions(&lxc_code);
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_SUCCEEDED(ret))
72 {
73 lxc_code_init = true;
74 }
75 }
76 1 return ret;
77 }
78
79 static void free_lxc_array(void** array, int count)
80 {
81 while(count-- > 0)
82 {
83 free(*array);
84 ++array;
85 }
86 }
87
88 /* LXC sandbox interface methods */
89
90 typedef struct lxcsbox_class
91 {
92 GATE_INTERFACE_VTBL(gate_virtualization_sandbox) const* vtbl;
93
94 gate_atomic_int_t ref_counter;
95 gate_string_t name;
96 gate_property_t settings;
97 } lxcsbox_t;
98
99 static void lxcsbox_destroy(lxcsbox_t* self)
100 {
101 gate_string_release(&self->name);
102 gate_property_destroy(&self->settings);
103 gate_mem_dealloc(self);
104 }
105
106 static char const* lxcsbox_get_interface_name(void* thisptr)
107 {
108 GATE_UNUSED_ARG(thisptr);
109 return GATE_INTERFACE_NAME_VIRTUALIZATION_SANDBOX;
110 }
111
112 static void lxcsbox_release(void* thisptr)
113 {
114 lxcsbox_t* const self = (lxcsbox_t*)thisptr;
115 if (gate_atomic_int_dec(&self->ref_counter) == 0)
116 {
117 lxcsbox_destroy(self);
118 }
119 }
120
121 static int lxcsbox_retain(void* thisptr)
122 {
123 lxcsbox_t* const self = (lxcsbox_t*)thisptr;
124 return gate_atomic_int_inc(&self->ref_counter);
125 }
126
127 static gate_result_t get_lxc_container_from_sandbox(lxcsbox_t* self, struct lxc_container** ptr_container)
128 {
129 gate_result_t ret;
130 gate_cstrbuffer_t buffer = GATE_INIT_EMPTY;
131 struct lxc_container* container = NULL;
132 do
133 {
134 if (NULL == gate_cstrbuffer_create_string(&buffer, &self->name, false))
135 {
136 GATE_DEBUG_TRACE("gate_cstrbuffer_create_string() failed");
137 ret = GATE_RESULT_OUTOFMEMORY;
138 break;
139 }
140 container = lxc_code.lxc_container_new(gate_cstrbuffer_get(&buffer), NULL);
141 if (NULL == container)
142 {
143 GATE_DEBUG_TRACE("lxc_container_new() failed");
144 ret = GATE_RESULT_FAILED;
145 break;
146 }
147 ret = GATE_RESULT_OK;
148 } while (0);
149 gate_cstrbuffer_destroy(&buffer);
150 *ptr_container = container;
151 return ret;
152 }
153
154 static void release_container(struct lxc_container** ptr_container)
155 {
156 GATE_DEBUG_ASSERT(ptr_container != NULL);
157 if (NULL != *ptr_container)
158 {
159 lxc_code.lxc_container_put(*ptr_container);
160 *ptr_container = NULL;
161 }
162 }
163
164 static gate_result_t lxcsbox_start(void* thisptr)
165 {
166 lxcsbox_t* const self = (lxcsbox_t*)thisptr;
167 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
168 struct lxc_container* ptr_container = NULL;
169 do
170 {
171 ret = get_lxc_container_from_sandbox(self, &ptr_container);
172 GATE_BREAK_IF_FAILED(ret);
173
174 if (!ptr_container->is_defined(ptr_container))
175 {
176 /* container not defined/existing */
177 ret = GATE_RESULT_NOTAVAILABLE;
178 break;
179 }
180
181 if (ptr_container->is_running(ptr_container))
182 {
183 /* container is already started -> start not supported */
184 ret = GATE_RESULT_INVALIDSTATE;
185 break;
186 }
187
188 if (!ptr_container->start(ptr_container, 0, NULL))
189 {
190 /* failed to start container */
191 ret = GATE_RESULT_FAILED;
192 break;
193 }
194
195 /* success case */
196 ret = GATE_RESULT_OK;
197 } while (0);
198
199 release_container(&ptr_container);
200 return ret;
201 }
202
203 static gate_result_t lxcsbox_stop(void* thisptr)
204 {
205 lxcsbox_t* const self = (lxcsbox_t*)thisptr;
206 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
207 struct lxc_container* ptr_container = NULL;
208 do
209 {
210 ret = get_lxc_container_from_sandbox(self, &ptr_container);
211 GATE_BREAK_IF_FAILED(ret);
212
213 if (!ptr_container->is_defined(ptr_container))
214 {
215 /* container not defined/existing */
216 ret = GATE_RESULT_NOTAVAILABLE;
217 break;
218 }
219
220 if (!ptr_container->is_running(ptr_container))
221 {
222 /* conainter is not running, stop not supported */
223 ret = GATE_RESULT_INVALIDSTATE;
224 break;
225 }
226
227 if (!ptr_container->stop(ptr_container))
228 {
229 /* failed to stop container */
230 ret = GATE_RESULT_FAILED;
231 break;
232 }
233
234 /* success case */
235 ret = GATE_RESULT_OK;
236 } while (0);
237
238 release_container(&ptr_container);
239 return ret;
240 }
241
242 static gate_enumint_t lxcsbox_get_status(void* thisptr)
243 {
244 lxcsbox_t* const self = (lxcsbox_t*)thisptr;
245 gate_enumint_t ret = GATE_VIRTUALIZATION_SANDBOX_STATUS_UNKNOWN;
246 struct lxc_container* ptr_container = NULL;
247 do
248 {
249 gate_result_t result = get_lxc_container_from_sandbox(self, &ptr_container);
250 GATE_BREAK_IF_FAILED(result);
251
252 if (!ptr_container->is_defined(ptr_container))
253 {
254 /* container not defined/existing */
255 ret = GATE_VIRTUALIZATION_SANDBOX_STATUS_UNKNOWN;
256 }
257 else
258 {
259 /* evaluate running state */
260 ret = ptr_container->is_running(ptr_container)
261 ? GATE_VIRTUALIZATION_SANDBOX_STATUS_ONLINE
262 : GATE_VIRTUALIZATION_SANDBOX_STATUS_OFFLINE
263 ;
264 }
265 } while (0);
266 release_container(&ptr_container);
267 return ret;
268 }
269
270 static gate_result_t lxcsbox_get_id(void* thisptr, gate_string_t* id)
271 {
272 lxcsbox_t* const self = (lxcsbox_t*)thisptr;
273 if (id)
274 {
275 gate_string_clone(id, &self->name);
276 }
277 return GATE_RESULT_OK;
278 }
279
280 static gate_result_t lxcsbox_get_name(void* thisptr, gate_string_t* name)
281 {
282 lxcsbox_t* const self = (lxcsbox_t*)thisptr;
283 if (name)
284 {
285 gate_string_clone(name, &self->name);
286 }
287 return GATE_RESULT_OK;
288 }
289
290 static gate_result_t lxcsbox_get_settings(void* thisptr, gate_property_t* settings)
291 {
292 lxcsbox_t* const self = (lxcsbox_t*)thisptr;
293 if (settings)
294 {
295 if (NULL == gate_property_copy(settings, &self->settings))
296 {
297 return GATE_RESULT_OUTOFMEMORY;
298 }
299 }
300 return GATE_RESULT_OK;
301 }
302
303 static gate_result_t lxcsbox_update_settings(void* thisptr, gate_property_t const* settings)
304 {
305 lxcsbox_t* const self = (lxcsbox_t*)thisptr;
306 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
307 /* TODO */
308 return ret;
309 }
310
311 static GATE_INTERFACE_VTBL(gate_virtualization_sandbox) const* lxcsbox_vtbl_init()
312 {
313 static GATE_INTERFACE_VTBL(gate_virtualization_sandbox) lxcsbox_vtbl;
314 if (lxcsbox_vtbl.get_interface_name == NULL)
315 {
316 GATE_INTERFACE_VTBL(gate_virtualization_sandbox) const vtbl = {
317 &lxcsbox_get_interface_name,
318 &lxcsbox_release,
319 &lxcsbox_retain,
320
321 &lxcsbox_start,
322 &lxcsbox_stop,
323 &lxcsbox_get_status,
324
325 &lxcsbox_get_id,
326 &lxcsbox_get_name,
327 &lxcsbox_get_settings,
328 &lxcsbox_update_settings
329 };
330 lxcsbox_vtbl = vtbl;
331 }
332 return &lxcsbox_vtbl;
333 }
334
335 static gate_result_t lxcsbox_create(gate_string_t const* name, lxcsbox_t** ptr_lxcsbox)
336 {
337 lxcsbox_t* ptr = (lxcsbox_t*)gate_mem_alloc(sizeof(lxcsbox_t));
338 if (NULL == ptr)
339 {
340 return GATE_RESULT_OUTOFMEMORY;
341 }
342 gate_mem_clear(ptr, sizeof(lxcsbox_t));
343 ptr->vtbl = lxcsbox_vtbl_init();
344 gate_atomic_int_init(&ptr->ref_counter, 1);
345 gate_string_clone(&ptr->name, name);
346 gate_property_create_object(&ptr->settings);
347 *ptr_lxcsbox = ptr;
348 return GATE_RESULT_OK;
349 }
350
351
352
353 /* LXC provider interface methods */
354
355 static char const* lxcprov_get_interface_name(void* obj)
356 {
357 GATE_UNUSED_ARG(obj);
358 return GATE_INTERFACE_NAME_VIRTUALIZATION_PROVIDER;
359 }
360 static void lxcprov_release(void* obj)
361 {
362 GATE_UNUSED_ARG(obj);
363 }
364 static int lxcprov_retain(void* obj)
365 {
366 GATE_UNUSED_ARG(obj);
367 return 1;
368 }
369 static gate_result_t lxcprov_get_name(void* obj, gate_string_t* name)
370 {
371 GATE_UNUSED_ARG(obj);
372 gate_string_create_static_len(name, "LXC", 3);
373 return GATE_RESULT_OK;
374 }
375 static gate_result_t lxcprov_get_settings(void* obj, gate_property_t* settings)
376 {
377 GATE_UNUSED_ARG(obj);
378 gate_property_create_object(settings);
379 return GATE_RESULT_OK;
380 }
381 static gate_result_t lxcprov_list_sandbox_ids(void* obj, gate_array_t* sandbox_ids)
382 {
383 GATE_UNUSED_ARG(obj);
384 gate_result_t ret = GATE_RESULT_FAILED;
385 char** names = NULL;
386 int found_containers;
387 gate_arraylist_t arr = NULL;
388
389 do
390 {
391 gate_size_t ndx;
392 char const* const lxcpath = NULL;
393 found_containers = lxc_code.list_all_containers(lxcpath, &names, NULL);
394 if (found_containers < 0)
395 {
396 ret = GATE_RESULT_FAILED;
397 break;
398 }
399
400 arr = gate_util_stringarray_create();
401 if (arr == NULL)
402 {
403 ret = GATE_RESULT_OUTOFMEMORY;
404 break;
405 }
406
407 for (ndx = 0; ndx < found_containers; ++ndx)
408 {
409 char const* name = names[ndx];
410 gate_util_stringarray_add_str(arr, name);
411 }
412
413 ret = GATE_RESULT_OK;
414 if (sandbox_ids)
415 {
416 if (NULL == gate_array_create(sandbox_ids, arr))
417 {
418 ret = GATE_RESULT_OUTOFMEMORY;
419 }
420 }
421 } while (0);
422
423 if (arr)
424 {
425 gate_arraylist_release(arr);
426 }
427 if (names)
428 {
429 free_lxc_array((void**)names, found_containers);
430 }
431
432 return ret;
433 }
434
435 static gate_result_t lxcprov_get_sandbox(void* obj, gate_string_t const* sandbox_id, gate_virtualization_sandbox_t** ptr_sandbox)
436 {
437 lxcsbox_t* ptr = NULL;
438 gate_result_t result = lxcsbox_create(sandbox_id, &ptr);
439 if (GATE_SUCCEEDED(result))
440 {
441 if (ptr_sandbox)
442 {
443 *ptr_sandbox = (gate_virtualization_sandbox_t*)ptr;
444 }
445 else
446 {
447 gate_object_release(ptr);
448 }
449 }
450 return result;
451 }
452
453
454 static gate_virtualization_provider_t* init_global_lxc_provider()
455 {
456 static gate_virtualization_provider_t lxc_prov;
457 static GATE_INTERFACE_VTBL(gate_virtualization_provider) lxc_prov_vtbl;
458
459 if (lxc_prov.vtbl == NULL)
460 {
461 GATE_INTERFACE_VTBL(gate_virtualization_provider) const vtbl = {
462 &lxcprov_get_interface_name,
463 &lxcprov_release,
464 &lxcprov_retain,
465
466 &lxcprov_get_name,
467 &lxcprov_get_settings,
468
469 &lxcprov_list_sandbox_ids,
470 &lxcprov_get_sandbox
471 };
472 lxc_prov_vtbl = vtbl;
473 lxc_prov.vtbl = &lxc_prov_vtbl;
474 }
475 return &lxc_prov;
476 }
477
478 #endif /* GATE_TECH_VIRTUALIZATION_LXC */
479
480
481
482 #if defined(GATE_TECH_VIRTUALIZATION_HYPERV2)
483
484 #include "gate/system/management.h"
485 #include "gate/utilities.h"
486
487 static gate_string_t const virtprov_name_hyperv2 = GATE_STRING_INIT_STATIC("mshyperv2");
488 static gate_string_t const virtprov_descr_hyperv2 = GATE_STRING_INIT_STATIC("Microsoft Hyper-V v2");
489
490 static gate_string_t const wmi_default_host = GATE_STRING_INIT_STATIC(".");
491 static gate_string_t const wmi_default_namespace = GATE_STRING_INIT_STATIC("ROOT\\virtualization\\v2");
492 static gate_string_t const wmi_search_path = GATE_STRING_INIT_STATIC("\\\\.\\ROOT\\virtualization\\v2");
493
494
495 typedef struct mshv2sbox_class
496 {
497 GATE_INTERFACE_VTBL(gate_virtualization_sandbox) const* vtbl;
498
499 gate_atomic_int_t ref_counter;
500 gate_management_t mgmt;
501 gate_string_t vm_path;
502 } mshv2sbox_t;
503
504 static void mshv2sbox_destroy(mshv2sbox_t* self)
505 {
506 if (self->mgmt)
507 {
508 gate_management_close(self->mgmt);
509 }
510 gate_string_release(&self->vm_path);
511
512 gate_mem_clear(self, sizeof(mshv2sbox_t));
513 gate_mem_dealloc(self);
514 }
515
516 static char const* mshv2sbox_get_interface_name(void* thisptr)
517 {
518 mshv2sbox_t* const self = (mshv2sbox_t*)thisptr;
519 return GATE_INTERFACE_NAME_VIRTUALIZATION_SANDBOX;
520 }
521 static void mshv2sbox_release(void* thisptr)
522 {
523 mshv2sbox_t* const self = (mshv2sbox_t*)thisptr;
524 if (gate_atomic_int_dec(&self->ref_counter) == 0)
525 {
526 mshv2sbox_destroy(self);
527 }
528 }
529 static int mshv2sbox_retain(void* thisptr)
530 {
531 mshv2sbox_t* const self = (mshv2sbox_t*)thisptr;
532 return gate_atomic_int_inc(&self->ref_counter);
533 }
534
535
536 static gate_result_t mshv2sbox_change_state(mshv2sbox_t* self, gate_int32_t new_state)
537 {
538 gate_result_t ret;
539 gate_map_t input_args = GATE_INIT_EMPTY;
540 gate_map_t output_args = GATE_INIT_EMPTY;
541 do
542 {
543 static gate_string_t const methodname = GATE_STRING_INIT_STATIC("RequestStateChange");
544 static gate_string_t const param_requestedstate = GATE_STRING_INIT_STATIC("RequestedState");
545 static gate_string_t const param_returnvalue = GATE_STRING_INIT_STATIC("ReturnValue");
546 gate_value_t const* ptr_retval = NULL;
547
548 if (NULL == gate_util_stringvaluemap_create_ex(&input_args, true, true))
549 {
550 ret = GATE_RESULT_OUTOFMEMORY;
551 break;
552 }
553 gate_util_stringvaluemap_add_string(&input_args, &param_requestedstate, GATE_TYPE_I32, &new_state);
554
555 ret = gate_management_invoke(self->mgmt, &self->vm_path, &methodname, &input_args, &output_args);
556 GATE_BREAK_IF_FAILED(ret);
557
558 ptr_retval = gate_util_stringvaluemap_get_string(&output_args, &param_returnvalue);
559 if (ptr_retval)
560 {
561 /* evaluate WMI return value */
562 gate_int32_t const* ptr_intretval = (gate_int32_t const*)gate_value_get_ptr(ptr_retval);
563 if (ptr_intretval)
564 {
565 gate_int32_t const rv = *ptr_intretval;
566 if ((rv == 0) || (rv == 4096))
567 {
568 ret = GATE_RESULT_OK;
569 }
570 else
571 {
572 ret = GATE_RESULT_EXECUTIONFAILED;
573 }
574 }
575 }
576 } while (0);
577
578 gate_map_destroy(&input_args);
579 gate_map_destroy(&output_args);
580 return ret;
581 }
582
583 static gate_result_t mshv2sbox_start(void* thisptr)
584 {
585 mshv2sbox_t* const self = (mshv2sbox_t*)thisptr;
586 static int const state_enabled = 2;
587 return mshv2sbox_change_state(self, state_enabled);
588 }
589 static gate_result_t mshv2sbox_stop(void* thisptr)
590 {
591 mshv2sbox_t* const self = (mshv2sbox_t*)thisptr;
592 static int const state_disabled = 3;
593 return mshv2sbox_change_state(self, state_disabled);
594 }
595
596 #define MSHV2SBOX_STATE_UNKNOWN 0
597 #define MSHV2SBOX_STATE_OTHER 1
598 #define MSHV2SBOX_STATE_ENABLED 2
599 #define MSHV2SBOX_STATE_DISABLED 3
600 #define MSHV2SBOX_STATE_SHUTDOWN 4
601 #define MSHV2SBOX_STATE_NOTAPPLICABLE 5
602 #define MSHV2SBOX_STATE_OFFLINE 6
603 #define MSHV2SBOX_STATE_TEST 7
604 #define MSHV2SBOX_STATE_DEFERRED 8
605 #define MSHV2SBOX_STATE_QUIESCE 9
606 #define MSHV2SBOX_STATE_STARTING 10
607
608 static gate_enumint_t mshv2sbox_get_status(void* thisptr)
609 {
610 mshv2sbox_t* const self = (mshv2sbox_t*)thisptr;
611 gate_management_object_t obj = GATE_INIT_EMPTY;
612 gate_enumint_t ret = GATE_VIRTUALIZATION_SANDBOX_STATUS_UNKNOWN;
613
614 do
615 {
616 static gate_string_t const keyEnabledState = GATE_STRING_INIT_STATIC("EnabledState");
617 gate_map_iterator_t iter;
618 gate_result_t result = gate_management_get_object(self->mgmt, &self->vm_path, &obj);
619 GATE_BREAK_IF_FAILED(result);
620
621 iter = gate_map_get(&obj.properties, &keyEnabledState);
622 if (!gate_map_iterator_valid(iter))
623 {
624 ret = GATE_VIRTUALIZATION_SANDBOX_STATUS_UNKNOWN;
625 break;
626 }
627 else
628 {
629 gate_value_t const* ptr_value = (gate_value_t const*)gate_map_iterator_value(iter);
630 gate_int32_t const* ptr_state;
631 if (gate_value_type(ptr_value) != GATE_TYPE_I32)
632 {
633 break;
634 }
635 ptr_state = (gate_int32_t const*)gate_value_get_ptr(ptr_value);
636 switch (*ptr_state)
637 {
638 case MSHV2SBOX_STATE_UNKNOWN:
639 case MSHV2SBOX_STATE_OTHER:
640 ret = GATE_VIRTUALIZATION_SANDBOX_STATUS_UNKNOWN;
641 break;
642 case MSHV2SBOX_STATE_ENABLED:
643 case MSHV2SBOX_STATE_QUIESCE:
644 case MSHV2SBOX_STATE_OFFLINE:
645 ret = GATE_VIRTUALIZATION_SANDBOX_STATUS_ONLINE;
646 break;
647 case MSHV2SBOX_STATE_DISABLED:
648 ret = GATE_VIRTUALIZATION_SANDBOX_STATUS_OFFLINE;
649 break;
650 case MSHV2SBOX_STATE_SHUTDOWN:
651 case MSHV2SBOX_STATE_NOTAPPLICABLE:
652 case MSHV2SBOX_STATE_TEST:
653 case MSHV2SBOX_STATE_DEFERRED:
654 case MSHV2SBOX_STATE_STARTING:
655 ret = GATE_VIRTUALIZATION_SANDBOX_STATUS_BUSY;
656 break;
657 }
658 }
659 } while (0);
660
661 gate_management_object_release(&obj);
662 return ret;
663 }
664
665 static gate_result_t mshv2sbox_get_id(void* thisptr, gate_string_t* id)
666 {
667 mshv2sbox_t* const self = (mshv2sbox_t*)thisptr;
668 gate_result_t ret;
669 gate_management_object_t obj = GATE_INIT_EMPTY;
670
671 do
672 {
673 static gate_string_t const keyName = GATE_STRING_INIT_STATIC("Name");
674 gate_map_iterator_t iter;
675 gate_value_t const* value;
676 gate_string_t const* strvalue;
677
678 ret = gate_management_get_object(self->mgmt, &self->vm_path, &obj);
679 GATE_BREAK_IF_FAILED(ret);
680
681 iter = gate_map_get(&obj.properties, &keyName);
682 if (!gate_map_iterator_valid(iter))
683 {
684 ret = GATE_RESULT_NOTAVAILABLE;
685 break;
686 }
687 value = (gate_value_t const*)gate_map_iterator_value(iter);
688 if (gate_value_type(value) != GATE_TYPE_STRING)
689 {
690 ret = GATE_RESULT_INCORRECTTYPE;
691 break;
692 }
693 strvalue = (gate_string_t const*)gate_value_get_ptr(value);
694 if (NULL == gate_string_clone(id, strvalue))
695 {
696 ret = GATE_RESULT_OUTOFMEMORY;
697 break;
698 }
699 ret = GATE_RESULT_OK;
700 } while (0);
701 gate_management_object_release(&obj);
702 return ret;
703 }
704 static gate_result_t mshv2sbox_get_name(void* thisptr, gate_string_t* name)
705 {
706 mshv2sbox_t* const self = (mshv2sbox_t*)thisptr;
707 gate_result_t ret;
708 gate_management_object_t obj = GATE_INIT_EMPTY;
709
710 do
711 {
712 static gate_string_t const keyName = GATE_STRING_INIT_STATIC("ElementName");
713 gate_map_iterator_t iter;
714 gate_value_t const* value;
715 gate_string_t const* strvalue;
716
717 ret = gate_management_get_object(self->mgmt, &self->vm_path, &obj);
718 GATE_BREAK_IF_FAILED(ret);
719
720 iter = gate_map_get(&obj.properties, &keyName);
721 if (!gate_map_iterator_valid(iter))
722 {
723 ret = GATE_RESULT_NOTAVAILABLE;
724 break;
725 }
726 value = (gate_value_t const*)gate_map_iterator_value(iter);
727 if (gate_value_type(value) != GATE_TYPE_STRING)
728 {
729 ret = GATE_RESULT_INCORRECTTYPE;
730 break;
731 }
732 strvalue = (gate_string_t const*)gate_value_get_ptr(value);
733 if (NULL == gate_string_clone(name, strvalue))
734 {
735 ret = GATE_RESULT_OUTOFMEMORY;
736 break;
737 }
738 ret = GATE_RESULT_OK;
739 } while (0);
740 gate_management_object_release(&obj);
741 return ret;
742 }
743 static gate_result_t mshv2sbox_get_settings(void* thisptr, gate_property_t* settings)
744 {
745 mshv2sbox_t* const self = (mshv2sbox_t*)thisptr;
746 gate_result_t ret;
747 do
748 {
749 if (NULL == gate_property_create_object(settings))
750 {
751 ret = GATE_RESULT_OUTOFMEMORY;
752 break;
753 }
754 /* TODO */
755 ret = GATE_RESULT_OK;
756 } while (0);
757 return ret;
758 }
759 static gate_result_t mshv2sbox_update_settings(void* thisptr, gate_property_t const* settings)
760 {
761 mshv2sbox_t* const self = (mshv2sbox_t*)thisptr;
762 gate_result_t ret;
763 do
764 {
765 /* TODO */
766 ret = GATE_RESULT_NOTSUPPORTED;
767 } while (0);
768 return ret;
769 }
770
771 static GATE_INTERFACE_VTBL(gate_virtualization_sandbox)* mshv2sbox_vtbl_init()
772 {
773 static GATE_INTERFACE_VTBL(gate_virtualization_sandbox) vtbl;
774 if (vtbl.get_interface_name == NULL)
775 {
776 GATE_INTERFACE_VTBL(gate_virtualization_sandbox) v =
777 {
778 &mshv2sbox_get_interface_name,
779 &mshv2sbox_release,
780 &mshv2sbox_retain,
781
782 &mshv2sbox_start,
783 &mshv2sbox_stop,
784 &mshv2sbox_get_status,
785
786 &mshv2sbox_get_id,
787 &mshv2sbox_get_name,
788 &mshv2sbox_get_settings,
789 &mshv2sbox_update_settings
790 };
791 vtbl = v;
792 }
793 return &vtbl;
794 }
795
796
797 static gate_result_t mshv2sbox_create(gate_string_t const* path, mshv2sbox_t** ptr_obj)
798 {
799 gate_result_t ret;
800 gate_management_t mgmt;
801 mshv2sbox_t* sbox = NULL;
802
803 do
804 {
805 sbox = (mshv2sbox_t*)gate_mem_alloc(sizeof(mshv2sbox_t));
806 if (sbox == NULL)
807 {
808 ret = GATE_RESULT_OUTOFMEMORY;
809 break;
810 }
811
812 gate_mem_clear(sbox, sizeof(mshv2sbox_t));
813 sbox->vtbl = mshv2sbox_vtbl_init();
814 gate_atomic_int_init(&sbox->ref_counter, 1);
815
816 gate_string_clone(&sbox->vm_path, path);
817 ret = gate_management_open(&wmi_default_host, NULL, &wmi_default_namespace, 0, &sbox->mgmt);
818 GATE_BREAK_IF_FAILED(ret);
819
820 *ptr_obj = sbox;
821 sbox = NULL;
822 ret = GATE_RESULT_OK;
823 } while (0);
824
825 if (sbox != NULL)
826 {
827 mshv2sbox_destroy(sbox);
828 }
829
830 return ret;
831 }
832
833
834 typedef struct mshv2prov_class
835 {
836 GATE_INTERFACE_VTBL(gate_virtualization_provider) const* vtbl;
837
838 gate_atomic_int_t ref_counter;
839 gate_management_t mgmt;
840 } mshv2prov_t;
841
842 static void mshv2prov_destroy(mshv2prov_t* self)
843 {
844 if (NULL != self->mgmt)
845 {
846 gate_management_close(self->mgmt);
847 }
848 gate_mem_clear(self, sizeof(mshv2prov_t));
849 gate_mem_dealloc(self);
850 }
851
852 static char const* mshv2prov_get_interface_name(void* thisptr)
853 {
854 mshv2prov_t* self = (mshv2prov_t*)thisptr;
855 return GATE_INTERFACE_NAME_VIRTUALIZATION_PROVIDER;
856 }
857
858 static void mshv2prov_release(void* thisptr)
859 {
860 mshv2prov_t* const self = (mshv2prov_t*)thisptr;
861 if (0 == gate_atomic_int_dec(&self->ref_counter))
862 {
863 mshv2prov_destroy(self);
864 }
865 }
866
867 static int mshv2prov_retain(void* thisptr)
868 {
869 mshv2prov_t* const self = (mshv2prov_t*)thisptr;
870 return gate_atomic_int_inc(&self->ref_counter);
871 }
872
873 static gate_result_t mshv2prov_get_name(void* thisptr, gate_string_t* name)
874 {
875 mshv2prov_t* const self = (mshv2prov_t*)thisptr;
876 gate_string_duplicate(name, &virtprov_name_hyperv2);
877 return GATE_RESULT_OK;
878 }
879
880 static gate_result_t mshv2prov_get_settings(void* thisptr, gate_property_t* settings)
881 {
882 mshv2prov_t* const self = (mshv2prov_t*)thisptr;
883 if (NULL == gate_property_create_object(settings))
884 {
885 return GATE_RESULT_OUTOFMEMORY;
886 }
887 return GATE_RESULT_OK;
888 }
889
890 static gate_bool_t GATE_CALL mshv2prov_list_callback(gate_management_object_t const* mgmt_obj, void* user_param)
891 {
892 gate_arraylist_t lst = (gate_arraylist_t)user_param;
893 static gate_string_t const keyInstallDate = GATE_STRING_INIT_STATIC("InstallDate");
894 static gate_string_t const keyName = GATE_STRING_INIT_STATIC("Name");
895 gate_map_iterator_t iterDate = gate_map_get(&mgmt_obj->properties, &keyInstallDate);
896 gate_map_iterator_t iterName = gate_map_get(&mgmt_obj->properties, &keyName);
897 if (gate_map_iterator_valid(iterDate) && gate_map_iterator_valid(iterName))
898 {
899 gate_value_t const* val_name = gate_map_iterator_value(iterName);
900 if (val_name && (gate_value_type(val_name) == GATE_TYPE_STRING))
901 {
902 gate_string_t const* name = (gate_string_t const*)gate_value_get_ptr(val_name);
903 gate_arraylist_add(lst, name);
904 }
905 }
906 return true;
907 }
908
909 static gate_string_t const search_query = GATE_STRING_INIT_STATIC("SELECT * FROM Msvm_ComputerSystem");
910
911 static gate_result_t mshv2prov_list_sandbox_ids(void* thisptr, gate_array_t* sandbox_ids)
912 {
913 mshv2prov_t* const self = (mshv2prov_t*)thisptr;
914 gate_result_t ret;
915 gate_arraylist_t lst = gate_util_stringarray_create();
916
917 do
918 {
919 if (NULL == lst)
920 {
921 ret = GATE_RESULT_OUTOFMEMORY;
922 break;
923 }
924
925 ret = gate_management_query(self->mgmt, &wmi_search_path, &search_query, &mshv2prov_list_callback, lst);
926 GATE_BREAK_IF_FAILED(ret);
927
928 if (NULL == gate_array_create(sandbox_ids, lst))
929 {
930 ret = GATE_RESULT_OUTOFMEMORY;
931 break;
932 }
933
934 ret = GATE_RESULT_OK;
935 } while (0);
936
937 if (NULL != lst)
938 {
939 gate_arraylist_release(lst);
940 }
941
942 return ret;
943 }
944
945 static gate_bool_t GATE_CALL mshv2prov_sandbox_callback(gate_management_object_t const* mgmt_obj, void* user_param)
946 {
947 gate_string_t* path = (gate_string_t*)user_param;
948 gate_string_clone(path, &mgmt_obj->path);
949 return false;
950 }
951
952 static gate_result_t mshv2prov_get_sandbox(void* thisptr, gate_string_t const* sandbox_id, gate_virtualization_sandbox_t** ptr_sandbox)
953 {
954 mshv2prov_t* const self = (mshv2prov_t*)thisptr;
955 mshv2sbox_t* mshv2sbox = NULL;
956 gate_result_t result;
957 gate_strbuilder_t builder;
958 gate_string_t query = GATE_STRING_INIT_EMPTY;
959 gate_string_t found_path = GATE_STRING_INIT_EMPTY;
960 char buffer[1024];
961
962 do
963 {
964 gate_strbuilder_create_static(&builder, buffer, sizeof(buffer), 0);
965
966 gate_strbuilder_append_string(&builder, &search_query);
967 gate_strbuilder_append_cstr(&builder, " WHERE Name=\"");
968 gate_strbuilder_append_string(&builder, sandbox_id);
969 gate_strbuilder_append_cstr(&builder, "\"");
970
971 if (NULL == gate_strbuilder_to_string(&builder, &query))
972 {
973 result = GATE_RESULT_OUTOFMEMORY;
974 break;
975 }
976
977 result = gate_management_query(self->mgmt, &wmi_search_path, &query, &mshv2prov_sandbox_callback, &found_path);
978 GATE_BREAK_IF_FAILED(result);
979
980 if (gate_string_is_empty(&found_path))
981 {
982 result = GATE_RESULT_NOMATCH;
983 break;
984 }
985
986 result = mshv2sbox_create(&found_path, &mshv2sbox);
987 if (GATE_SUCCEEDED(result))
988 {
989 if (ptr_sandbox)
990 {
991 *ptr_sandbox = (gate_virtualization_sandbox_t*)mshv2sbox;
992 }
993 else
994 {
995 gate_object_release(mshv2sbox);
996 }
997 }
998 } while (0);
999
1000 gate_string_release(&found_path);
1001 gate_string_release(&query);
1002 gate_strbuilder_release(&builder);
1003
1004 return result;
1005 }
1006
1007 static GATE_INTERFACE_VTBL(gate_virtualization_provider) const* init_virutalization_provider_vtbl()
1008 {
1009 static GATE_INTERFACE_VTBL(gate_virtualization_provider) vtbl;
1010 if (vtbl.get_interface_name == NULL)
1011 {
1012 GATE_INTERFACE_VTBL(gate_virtualization_provider) v =
1013 {
1014 &mshv2prov_get_interface_name,
1015 &mshv2prov_release,
1016 &mshv2prov_retain,
1017
1018 &mshv2prov_get_name,
1019 &mshv2prov_get_settings,
1020
1021 &mshv2prov_list_sandbox_ids,
1022 &mshv2prov_get_sandbox
1023 };
1024 vtbl = v;
1025 }
1026 return &vtbl;
1027 }
1028
1029 static gate_result_t mshv2prov_create(gate_string_t const* host, gate_virtualization_provider_t** ptr)
1030 {
1031 gate_result_t ret;
1032 mshv2prov_t* mshv2prov = NULL;
1033
1034 do
1035 {
1036 mshv2prov = (mshv2prov_t*)gate_mem_alloc(sizeof(mshv2prov_t));
1037 if (NULL == mshv2prov)
1038 {
1039 ret = GATE_RESULT_OUTOFMEMORY;
1040 break;
1041 }
1042 gate_mem_clear(mshv2prov, sizeof(mshv2prov_t));
1043 mshv2prov->vtbl = init_virutalization_provider_vtbl();
1044 gate_atomic_int_init(&mshv2prov->ref_counter, 1);
1045
1046 if (gate_string_is_empty(host))
1047 {
1048 host = &wmi_default_host;
1049 }
1050
1051 ret = gate_management_open(host, NULL, &wmi_default_namespace, 0, &mshv2prov->mgmt);
1052 GATE_BREAK_IF_FAILED(ret);
1053
1054 if (ptr != NULL)
1055 {
1056 *ptr = (gate_virtualization_provider_t*)mshv2prov;
1057 mshv2prov = NULL;
1058 }
1059 ret = GATE_RESULT_OK;
1060 } while (0);
1061
1062 if (NULL != mshv2prov)
1063 {
1064 gate_mem_dealloc(mshv2prov);
1065 }
1066 return ret;
1067 }
1068
1069 #endif /* GATE_TECH_VIRTUALIZATION_HYPERV2 */
1070
1071
1072
1073 #if defined(GATE_TECH_VIRTUALIZATION_WSL)
1074
1075 #include "gate/tech/platform/gate_wsl.h"
1076
1077 static gate_string_t const virtprov_name_wsl = GATE_STRING_INIT_STATIC("wsl");
1078 static gate_string_t const virtprov_descr_wsl = GATE_STRING_INIT_STATIC("Windows Subsystem for Linux");
1079
1080 typedef struct wsl_virtualization_provider_class
1081 {
1082 GATE_INTERFACE_VTBL(gate_virtualization_provider) const* vtbl;
1083
1084 gate_atomic_int_t ref_counter;
1085 } wsl_virtualization_provider_t;
1086
1087 static char const* wsl_get_interface_name(void* thisptr)
1088 {
1089 GATE_UNUSED_ARG(thisptr);
1090 return GATE_INTERFACE_NAME_VIRTUALIZATION_PROVIDER;
1091 }
1092 static void wsl_destroy(wsl_virtualization_provider_t* self)
1093 {
1094 gate_mem_dealloc(self);
1095 }
1096 static void wsl_release(void* thisptr)
1097 {
1098 wsl_virtualization_provider_t* self = (wsl_virtualization_provider_t*)thisptr;
1099 if (gate_atomic_int_dec(&self->ref_counter) == 0)
1100 {
1101 wsl_destroy(self);
1102 }
1103 }
1104 static int wsl_retain(void* thisptr)
1105 {
1106 wsl_virtualization_provider_t* self = (wsl_virtualization_provider_t*)thisptr;
1107 return gate_atomic_int_inc(&self->ref_counter);
1108 }
1109
1110 static gate_result_t wsl_get_name(void* thisptr, gate_string_t* name)
1111 {
1112 wsl_virtualization_provider_t* self = (wsl_virtualization_provider_t*)thisptr;
1113 gate_string_duplicate(name, &virtprov_name_wsl);
1114 return GATE_RESULT_OK;
1115 }
1116 static gate_result_t wsl_get_settings(void* thisptr, gate_property_t* settings)
1117 {
1118 wsl_virtualization_provider_t* self = (wsl_virtualization_provider_t*)thisptr;
1119 gate_property_create_empty(settings);
1120 return GATE_RESULT_OK;
1121 }
1122 static gate_result_t wsl_list_sandbox_ids(void* thisptr, gate_array_t* sandbox_ids)
1123 {
1124 wsl_virtualization_provider_t* self = (wsl_virtualization_provider_t*)thisptr;
1125 /* TODO */
1126 /* HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss */
1127 return GATE_RESULT_NOTIMPLEMENTED;
1128 }
1129 static gate_result_t wsl_get_sandbox(void* thisptr, gate_string_t const* sandbox_id, gate_virtualization_sandbox_t** ptr_sandbox)
1130 {
1131 wsl_virtualization_provider_t* self = (wsl_virtualization_provider_t*)thisptr;
1132 /* TODO */
1133 return GATE_RESULT_NOTIMPLEMENTED;
1134 }
1135
1136 static GATE_INTERFACE_VTBL(gate_virtualization_provider) const* wsl_provider_vtbl_init()
1137 {
1138 static GATE_INTERFACE_VTBL(gate_virtualization_provider) vtbl;
1139 if (vtbl.get_interface_name == NULL)
1140 {
1141 GATE_INTERFACE_VTBL(gate_virtualization_provider) v = {
1142 &wsl_get_interface_name,
1143 &wsl_release,
1144 &wsl_retain,
1145
1146 &wsl_get_name,
1147 &wsl_get_settings,
1148 &wsl_list_sandbox_ids,
1149 &wsl_get_sandbox
1150 };
1151 vtbl = v;
1152 }
1153 return &vtbl;
1154 }
1155
1156 static gate_result_t wsl_provider_create(gate_virtualization_provider_t** ptr_provider)
1157 {
1158 gate_result_t ret = GATE_RESULT_FAILED;
1159 wsl_virtualization_provider_t* wsl_prov = NULL;
1160 do
1161 {
1162 GATE_INTERFACE_VTBL(gate_virtualization_provider) const* vtbl = wsl_provider_vtbl_init();
1163 wsl_api_t* wsl = load_wsl_functions();
1164
1165 if (wsl == NULL)
1166 {
1167 ret = GATE_RESULT_NOTAVAILABLE;
1168 }
1169
1170 wsl_prov = (wsl_virtualization_provider_t*)gate_mem_alloc(sizeof(wsl_virtualization_provider_t));
1171 if (wsl_prov == NULL)
1172 {
1173 ret = GATE_RESULT_OUTOFMEMORY;
1174 break;
1175 }
1176
1177 wsl_prov->vtbl = vtbl;
1178 gate_atomic_int_init(&wsl_prov->ref_counter, 1);
1179
1180 /* success case reached: */
1181 *ptr_provider = (gate_virtualization_provider_t*)wsl_prov;
1182 wsl_prov = NULL;
1183 ret = GATE_RESULT_OK;
1184 } while (0);
1185
1186 if (wsl_prov)
1187 {
1188 wsl_release(wsl_prov);
1189 }
1190 return ret;
1191 }
1192
1193 #endif /* GATE_TECH_VIRTUALIZATION_WSL */
1194
1195
1196
1197 1 gate_result_t gate_tech_virtualization_providers_enum(gate_tech_virtualization_providers_callback_t callback, void* param)
1198 {
1199 1 gate_result_t ret = GATE_RESULT_OK;
1200
1201 do
1202 {
1203 #if defined(GATE_TECH_VIRTUALIZATION_LXC)
1204 /* lxc support */
1205
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (GATE_SUCCEEDED(gate_lxc_init()))
1206 {
1207 if (!callback(&virtprov_name_lxc, &virtprov_descr_lxc, param))
1208 {
1209 break;
1210 }
1211 }
1212 #endif /* GATE_TECH_VIRTUALIZATION_LXC */
1213
1214 #if defined(GATE_TECH_VIRTUALIZATION_HYPERV2)
1215 /* MS hyper-v wmi access */
1216 if (!callback(&virtprov_name_hyperv2, &virtprov_descr_hyperv2, param))
1217 {
1218 break;
1219 }
1220 #endif /* GATE_TECH_VIRTUALIZATION_HYPERV2 */
1221
1222 #if defined(GATE_TECH_VIRTUALIZATION_WSL)
1223 if (!callback(&virtprov_name_wsl, &virtprov_descr_wsl, param))
1224 {
1225 break;
1226 }
1227 #endif /* GATE_TECH_VIRTUALIZATION_WSL */
1228
1229 #if defined(GATE_TECH_VIRTUALIZATION_DOCKER)
1230 /* docker support */
1231
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!callback(&virtprov_name_docker, &virtprov_descr_docker, param))
1232 {
1233 break;
1234 }
1235 #endif /* GATE_TECH_VIRTUALIZATION_DOCKER */
1236
1237 } while (0);
1238
1239 1 return ret;
1240 }
1241
1242
1243 1 gate_result_t gate_tech_virtualization_provider_create(gate_string_t const* name, gate_virtualization_provider_t** ptr_provider)
1244 {
1245 1 gate_result_t ret = GATE_RESULT_NOMATCH;
1246
1247 do
1248 {
1249 #if defined(GATE_TECH_VIRTUALIZATION_LXC)
1250
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (gate_string_equals(name, &virtprov_name_lxc))
1251 {
1252 ret = gate_lxc_init();
1253 GATE_BREAK_IF_FAILED(ret);
1254
1255 if (ptr_provider)
1256 {
1257 gate_virtualization_provider_t* prov = init_global_lxc_provider();
1258 if (!prov)
1259 {
1260 ret = GATE_RESULT_FAILED;
1261 break;
1262 }
1263 *ptr_provider = prov;
1264 }
1265 ret = GATE_RESULT_OK;
1266 break;
1267 }
1268 #endif /* GATE_TECH_VIRTUALIZATION_LXC */
1269
1270 #if defined(GATE_TECH_VIRTUALIZATION_HYPERV2)
1271 if (gate_string_equals(name, &virtprov_name_hyperv2))
1272 {
1273 ret = mshv2prov_create(NULL, ptr_provider);
1274 return ret;
1275 }
1276 #endif /* GATE_TECH_VIRTUALIZATION_HYPERV2 */
1277
1278 #if defined(GATE_TECH_VIRTUALIZATION_WSL)
1279 if (gate_string_equals(name, &virtprov_name_wsl))
1280 {
1281 ret = wsl_provider_create(ptr_provider);
1282 return ret;
1283 }
1284 #endif /* GATE_TECH_VIRTUALIZATION_WSL */
1285
1286 #if defined(GATE_TECH_VIRTUALIZATION_DOCKER)
1287
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (gate_string_equals(name, &virtprov_name_docker))
1288 {
1289 /* TODO */
1290 1 ret = GATE_RESULT_FAILED;
1291 1 break;
1292 }
1293 #endif /* GATE_TECH_VIRTUALIZATION_DOCKER */
1294
1295 ret = GATE_RESULT_NOMATCH;
1296 } while (0);
1297
1298 1 return ret;
1299 }
1300