Implement virDomain(Get|Set)Metadata functions
[libvirt-php.git] / src / libvirt-php.c
1 /*
2 * libvirt-php.c: Core of the PHP bindings library/module
3 *
4 * See COPYING for the license of this software
5 *
6 * Written by:
7 *   Radek Hladik <r.hladik@cybersales.cz>
8 *   Michal Novotny <minovotn@redhat.com>
9 *   David King
10 *   Jan-Paul van Burgsteden
11 *   Lyre <liyong@skybility.com> (or <4179e1@gmail.com>)
12 *   Daniel P. Berrange <berrange@redhat.com>
13 *   Tiziano Mueller <dev-zero@gentoo.org>
14 *   Yukihiro Kawada <warp.kawada@gmail.com>
15 */
16
17 #include "libvirt-php.h"
18
19 // From vncfunc.c
20 int vnc_get_dimensions(char *server, char *port, int *width, int *height);
21 // From sockets.c
22 int connect_socket(char *server, char *port, int keepalive, int nodelay, int allow_server_override);
23
24 #ifdef DEBUG_CORE
25 #define DPRINTF(fmt, ...) \
26 if (LIBVIRT_G(debug)) \
27 do { fprintf(stderr, "[%s ", get_datetime()); fprintf(stderr, "libvirt-php/core   ]: " fmt , ## __VA_ARGS__); fflush(stderr); } while (0)
28 #else
29 #define DPRINTF(fmt, ...) \
30 do {} while(0)
31 #endif
32
33 /* PHP functions are prefixed with `zif_` so strip it */
34 #define PHPFUNC (__FUNCTION__ + 4)
35
36 /* Additional binaries */
37 char *features[] = { "screenshot", "create-image", "screenshot-convert", NULL };
38 char *features_binaries[] = { "/usr/bin/gvnccapture", "/usr/bin/qemu-img", "/bin/convert", NULL };
39
40 /* ZEND thread safe per request globals definition */
41 int le_libvirt_connection;
42 int le_libvirt_domain;
43 int le_libvirt_storagepool;
44 int le_libvirt_volume;
45 int le_libvirt_network;
46 int le_libvirt_nodedev;
47 #if LIBVIR_VERSION_NUMBER>=8000
48 int le_libvirt_snapshot;
49 #endif
50
51 ZEND_DECLARE_MODULE_GLOBALS(libvirt)
52
53 ZEND_BEGIN_ARG_INFO_EX(arginfo_libvirt_connect, 0, 0, 0)
54         ZEND_ARG_INFO(0, url)
55         ZEND_ARG_INFO(0, readonly)
56 ZEND_END_ARG_INFO()
57
58 static zend_function_entry libvirt_functions[] = {
59         /* Common functions */
60         PHP_FE(libvirt_get_last_error,NULL)
61         /* Connect functions */
62         PHP_FE(libvirt_connect, arginfo_libvirt_connect)
63         PHP_FE(libvirt_connect_get_uri, NULL)
64         PHP_FE(libvirt_connect_get_hostname, NULL)
65         PHP_FE(libvirt_connect_get_capabilities, NULL)
66         PHP_FE(libvirt_connect_get_emulator, NULL)
67         PHP_FE(libvirt_connect_get_nic_models, NULL)
68         PHP_FE(libvirt_connect_get_soundhw_models, NULL)
69         PHP_FE(libvirt_connect_get_information, NULL)
70         PHP_FE(libvirt_connect_get_machine_types, NULL)
71         PHP_FE(libvirt_connect_get_hypervisor, NULL)
72         PHP_FE(libvirt_connect_get_sysinfo, NULL)
73         PHP_FE(libvirt_connect_get_maxvcpus, NULL)
74         PHP_FE(libvirt_connect_get_encrypted, NULL)
75         PHP_FE(libvirt_connect_get_secure, NULL)
76         /* Domain functions */
77         PHP_FE(libvirt_domain_new, NULL)
78         PHP_FE(libvirt_domain_new_get_vnc, NULL)
79         PHP_FE(libvirt_domain_get_counts, NULL)
80         PHP_FE(libvirt_domain_is_persistent, NULL)
81         PHP_FE(libvirt_domain_lookup_by_name, NULL)
82         PHP_FE(libvirt_domain_get_xml_desc, NULL)
83         PHP_FE(libvirt_domain_get_disk_devices, NULL)
84         PHP_FE(libvirt_domain_get_interface_devices, NULL)
85         PHP_FE(libvirt_domain_change_vcpus, NULL)
86         PHP_FE(libvirt_domain_change_memory, NULL)
87         PHP_FE(libvirt_domain_change_boot_devices, NULL)
88         PHP_FE(libvirt_domain_disk_add, NULL)
89         PHP_FE(libvirt_domain_disk_remove, NULL)
90         PHP_FE(libvirt_domain_nic_add, NULL)
91         PHP_FE(libvirt_domain_nic_remove, NULL)
92         PHP_FE(libvirt_domain_get_info, NULL)
93         PHP_FE(libvirt_domain_get_name, NULL)
94         PHP_FE(libvirt_domain_get_uuid, NULL)
95         PHP_FE(libvirt_domain_get_uuid_string, NULL)
96         PHP_FE(libvirt_domain_get_id, NULL)
97         PHP_FE(libvirt_domain_lookup_by_id, NULL)
98         PHP_FE(libvirt_domain_lookup_by_uuid, NULL)
99         PHP_FE(libvirt_domain_lookup_by_uuid_string, NULL)
100         PHP_FE(libvirt_domain_destroy, NULL)
101         PHP_FE(libvirt_domain_create, NULL)
102         PHP_FE(libvirt_domain_resume, NULL)
103         PHP_FE(libvirt_domain_core_dump, NULL)
104         PHP_FE(libvirt_domain_shutdown, NULL)
105         PHP_FE(libvirt_domain_suspend, NULL)
106         PHP_FE(libvirt_domain_managedsave, NULL)
107         PHP_FE(libvirt_domain_undefine, NULL)
108         PHP_FE(libvirt_domain_reboot, NULL)
109         PHP_FE(libvirt_domain_define_xml, NULL)
110         PHP_FE(libvirt_domain_create_xml, NULL)
111         PHP_FE(libvirt_domain_memory_peek,NULL)
112         PHP_FE(libvirt_domain_memory_stats,NULL)
113         PHP_FE(libvirt_domain_block_stats,NULL)
114         PHP_FE(libvirt_domain_interface_stats,NULL)
115         PHP_FE(libvirt_domain_get_connect, NULL)
116         PHP_FE(libvirt_domain_migrate, NULL)
117         PHP_FE(libvirt_domain_migrate_to_uri, NULL)
118         PHP_FE(libvirt_domain_migrate_to_uri2, NULL)
119         PHP_FE(libvirt_domain_get_job_info, NULL)
120         PHP_FE(libvirt_domain_xml_xpath, NULL)
121         PHP_FE(libvirt_domain_get_block_info, NULL)
122         PHP_FE(libvirt_domain_get_network_info, NULL)
123         PHP_FE(libvirt_domain_get_autostart, NULL)
124         PHP_FE(libvirt_domain_set_autostart, NULL)
125         PHP_FE(libvirt_domain_get_metadata, NULL)
126         PHP_FE(libvirt_domain_set_metadata, NULL)
127         PHP_FE(libvirt_domain_is_active, NULL)
128         PHP_FE(libvirt_domain_get_next_dev_ids, NULL)
129         PHP_FE(libvirt_domain_get_screenshot, NULL)
130         PHP_FE(libvirt_domain_get_screenshot_api, NULL)
131         PHP_FE(libvirt_domain_get_screen_dimensions, NULL)
132         PHP_FE(libvirt_domain_send_keys, NULL)
133         PHP_FE(libvirt_domain_send_pointer_event, NULL)
134         PHP_FE(libvirt_domain_update_device, NULL)
135         /* Domain snapshot functions */
136         PHP_FE(libvirt_domain_has_current_snapshot, NULL)
137         PHP_FE(libvirt_domain_snapshot_create, NULL)
138         PHP_FE(libvirt_domain_snapshot_get_xml, NULL)
139         PHP_FE(libvirt_domain_snapshot_revert, NULL)
140         PHP_FE(libvirt_domain_snapshot_delete, NULL)
141         PHP_FE(libvirt_domain_snapshot_lookup_by_name, NULL)
142         /* Storagepool functions */
143         PHP_FE(libvirt_storagepool_lookup_by_name,NULL)
144         PHP_FE(libvirt_storagepool_lookup_by_volume,NULL)
145         PHP_FE(libvirt_storagepool_get_info,NULL)
146         PHP_FE(libvirt_storagevolume_lookup_by_name,NULL)
147         PHP_FE(libvirt_storagevolume_lookup_by_path,NULL)
148         PHP_FE(libvirt_storagevolume_get_name,NULL)
149         PHP_FE(libvirt_storagevolume_get_path,NULL)
150         PHP_FE(libvirt_storagevolume_get_info,NULL)
151         PHP_FE(libvirt_storagevolume_get_xml_desc,NULL)
152         PHP_FE(libvirt_storagevolume_create_xml,NULL)
153         PHP_FE(libvirt_storagevolume_create_xml_from,NULL)
154         PHP_FE(libvirt_storagevolume_delete,NULL)
155         PHP_FE(libvirt_storagepool_get_uuid_string, NULL)
156         PHP_FE(libvirt_storagepool_get_name, NULL)
157         PHP_FE(libvirt_storagepool_lookup_by_uuid_string, NULL)
158         PHP_FE(libvirt_storagepool_get_xml_desc, NULL)
159         PHP_FE(libvirt_storagepool_define_xml, NULL)
160         PHP_FE(libvirt_storagepool_undefine, NULL)
161         PHP_FE(libvirt_storagepool_create, NULL)
162         PHP_FE(libvirt_storagepool_destroy, NULL)
163         PHP_FE(libvirt_storagepool_is_active, NULL)
164         PHP_FE(libvirt_storagepool_get_volume_count, NULL)
165         PHP_FE(libvirt_storagepool_refresh, NULL)
166         PHP_FE(libvirt_storagepool_set_autostart, NULL)
167         PHP_FE(libvirt_storagepool_get_autostart, NULL)
168         PHP_FE(libvirt_storagepool_build, NULL)
169         PHP_FE(libvirt_storagepool_delete, NULL)
170         /* Network functions */
171         PHP_FE(libvirt_network_define_xml, NULL)
172         PHP_FE(libvirt_network_undefine, NULL)
173         PHP_FE(libvirt_network_get, NULL)
174         PHP_FE(libvirt_network_get_xml_desc, NULL)
175         PHP_FE(libvirt_network_get_bridge, NULL)
176         PHP_FE(libvirt_network_get_information, NULL)
177         PHP_FE(libvirt_network_get_active, NULL)
178         PHP_FE(libvirt_network_set_active, NULL)
179         /* Node functions */
180         PHP_FE(libvirt_node_get_info, NULL)
181         PHP_FE(libvirt_node_get_cpu_stats, NULL)
182         PHP_FE(libvirt_node_get_cpu_stats_for_each_cpu, NULL)
183         PHP_FE(libvirt_node_get_mem_stats, NULL)
184         /* Nodedev functions */
185         PHP_FE(libvirt_nodedev_get, NULL)
186         PHP_FE(libvirt_nodedev_capabilities, NULL)
187         PHP_FE(libvirt_nodedev_get_xml_desc, NULL)
188         PHP_FE(libvirt_nodedev_get_information, NULL)
189         /* List functions */
190         PHP_FE(libvirt_list_domains, NULL)
191         PHP_FE(libvirt_list_domain_snapshots, NULL)
192         PHP_FE(libvirt_list_domain_resources, NULL)
193         PHP_FE(libvirt_list_nodedevs, NULL)
194         PHP_FE(libvirt_list_networks,NULL)
195         PHP_FE(libvirt_list_storagepools,NULL)
196         PHP_FE(libvirt_list_active_storagepools,NULL)
197         PHP_FE(libvirt_list_inactive_storagepools,NULL)
198         PHP_FE(libvirt_storagepool_list_volumes,NULL)
199         PHP_FE(libvirt_list_active_domains, NULL)
200         PHP_FE(libvirt_list_active_domain_ids, NULL)
201         PHP_FE(libvirt_list_inactive_domains, NULL)
202         /* Version information and common function */
203         PHP_FE(libvirt_version, NULL)
204         PHP_FE(libvirt_check_version, NULL)
205         PHP_FE(libvirt_has_feature, NULL)
206         PHP_FE(libvirt_get_iso_images, NULL)
207         PHP_FE(libvirt_image_create, NULL)
208         PHP_FE(libvirt_image_remove, NULL)
209         /* Debugging functions */
210         PHP_FE(libvirt_logfile_set, NULL)
211         PHP_FE(libvirt_print_binding_resources, NULL)
212         {NULL, NULL, NULL}
213 };
214
215
216 /* Zend module basic definition  */
217 zend_module_entry libvirt_module_entry = {
218 #if ZEND_MODULE_API_NO >= 20010901
219     STANDARD_MODULE_HEADER,
220 #endif
221     PHP_LIBVIRT_WORLD_EXTNAME,
222     libvirt_functions,
223     PHP_MINIT(libvirt),
224     PHP_MSHUTDOWN(libvirt),
225     PHP_RINIT(libvirt),
226     PHP_RSHUTDOWN(libvirt),
227     PHP_MINFO(libvirt),
228 #if ZEND_MODULE_API_NO >= 20010901
229     PHP_LIBVIRT_WORLD_VERSION,
230 #endif
231     STANDARD_MODULE_PROPERTIES
232 };
233
234 #ifdef COMPILE_DL_LIBVIRT
235 ZEND_GET_MODULE(libvirt)
236 #endif
237
238 /* PHP init options */
239 PHP_INI_BEGIN()
240         STD_PHP_INI_ENTRY("libvirt.longlong_to_string", "1", PHP_INI_ALL, OnUpdateBool, longlong_to_string_ini, zend_libvirt_globals, libvirt_globals)
241         STD_PHP_INI_ENTRY("libvirt.iso_path", "/var/lib/libvirt/images/iso", PHP_INI_ALL, OnUpdateString, iso_path_ini, zend_libvirt_globals, libvirt_globals)
242         STD_PHP_INI_ENTRY("libvirt.image_path", "/var/lib/libvirt/images", PHP_INI_ALL, OnUpdateString, image_path_ini, zend_libvirt_globals, libvirt_globals)
243         STD_PHP_INI_ENTRY("libvirt.max_connections", "5", PHP_INI_ALL, OnUpdateString, max_connections_ini, zend_libvirt_globals, libvirt_globals)
244 PHP_INI_END()
245
246 void change_debug(int val TSRMLS_DC)
247 {
248         LIBVIRT_G(debug) = val;
249         gdebug = val;
250 }
251
252 /* PHP requires to have this function defined */
253 static void php_libvirt_init_globals(zend_libvirt_globals *libvirt_globals TSRMLS_DC)
254 {
255         libvirt_globals->longlong_to_string_ini = 1;
256         libvirt_globals->iso_path_ini = "/var/lib/libvirt/images/iso";
257         libvirt_globals->image_path_ini = "/var/lib/libvirt/images";
258         libvirt_globals->max_connections_ini = "5";
259         libvirt_globals->binding_resources_count = 0;
260         libvirt_globals->binding_resources = NULL;
261         #ifdef DEBUG_SUPPORT
262         libvirt_globals->debug = 0;
263         change_debug(0 TSRMLS_CC);
264         #endif
265 }
266
267 /* PHP request initialization */
268 PHP_RINIT_FUNCTION(libvirt)
269 {
270         LIBVIRT_G(last_error) = NULL;
271         LIBVIRT_G(vnc_location) = NULL;
272         change_debug(0 TSRMLS_CC);
273         return SUCCESS;
274 }
275
276 /* PHP request destruction */
277 PHP_RSHUTDOWN_FUNCTION(libvirt)
278 {
279         if (LIBVIRT_G (last_error)!=NULL) efree(LIBVIRT_G (last_error));
280         if (LIBVIRT_G (vnc_location)!=NULL) efree(LIBVIRT_G (vnc_location));
281         return SUCCESS;
282 }
283
284 /*
285         Private function name:  get_datetime
286         Since version:          0.4.2
287         Description:            Function can be used to get date and time in the `YYYY-mm-dd HH:mm:ss` format, internally used for logging when debug logging is enabled using libvirt_set_logfile() API function.
288         Arguments:              None
289         Returns:                Date/time string in `YYYY-mm-dd HH:mm:ss` format
290 */
291 char *get_datetime(void)
292 {
293         /* Caution: Function cannot use DPRINTF() macro otherwise the neverending loop will be met! */
294         char *outstr = NULL;
295         time_t t;
296         struct tm *tmp;
297
298         t = time(NULL);
299         tmp = localtime(&t);
300         if (tmp == NULL)
301                 return NULL;
302
303         outstr = (char *)malloc( 32 * sizeof(char) );
304         if (strftime(outstr, 32, "%Y-%m-%d %H:%M:%S", tmp) == 0)
305                 return NULL;
306
307         return outstr;
308 }
309
310 /*
311         Private function name:  set_logfile
312         Since version:          0.4.2
313         Description:            Function to set the log file. You can set log file to NULL to disable logging (default). Useful for debugging purposes.
314         Arguments:              @filename [string]: name of log file or NULL to disable
315                                 @maxsize [long]: integer value of maximum file size, file will be truncated after reaching max file size. Value is set in KiB.
316         Returns:                0 on success, -errno otherwise
317 */
318 int set_logfile(char *filename, long maxsize TSRMLS_DC)
319 {
320         int res;
321         struct stat st;
322
323         if (filename == NULL) {
324                 change_debug(0 TSRMLS_CC);
325                 return 0;
326         }
327
328         /* Convert from KiB to bytes and check whether file size exceeds maxsize */
329         maxsize *= 1024;
330         if (access(filename, F_OK) == 0) {
331                 stat(filename, &st);
332                 if (st.st_size > maxsize)
333                         unlink(filename);
334         }
335
336         res = (freopen(filename, "a", stderr) != NULL) ? 0 : -errno;
337         if (res == 0)
338                 change_debug(1 TSRMLS_CC);
339         return res;
340 }
341
342 /*
343         Private function name:  translate_counter_type
344         Since version:          0.4.2
345         Description:            Function to translate the counter type into the string format
346         Arguments:              @type [int]: integer identifier of the counter type
347         Returns:                string interpretation of the counter type
348 */
349 char *translate_counter_type(int type)
350 {
351         switch (type) {
352                 case INT_RESOURCE_CONNECTION:   return "connection";
353                                                 break;
354                 case INT_RESOURCE_DOMAIN:       return "domain";
355                                                 break;
356                 case INT_RESOURCE_NETWORK:      return "network";
357                                                 break;
358                 case INT_RESOURCE_NODEDEV:      return "node device";
359                                                 break;
360                 case INT_RESOURCE_STORAGEPOOL:  return "storage pool";
361                                                 break;
362                 case INT_RESOURCE_VOLUME:       return "storage volume";
363                                                 break;
364                 case INT_RESOURCE_SNAPSHOT:     return "snapshot";
365                                                 break;
366         }
367
368         return "unknown";
369 }
370
371 /*
372         Private function name:  tokenize
373         Since version:          0.4.9
374         Description:            Function to tokenize string into tokens by delimiter $by
375         Arguments:              @string [string]: input string
376                                 @by [string]: string used as delimited
377         Returns:                tTokenizer structure
378 */
379 tTokenizer tokenize(char *string, char *by)
380 {
381         char *tmp;
382         char *str;
383         char *save;
384         char *token;
385         int i = 0;
386         tTokenizer t;
387
388         tmp = strdup(string);
389         t.tokens = (char **)malloc( sizeof(char *) );
390         for (str = tmp; ; str = NULL) {
391                 token = strtok_r(str, by, &save);
392                 if (token == NULL)
393                         break;
394
395                 t.tokens = realloc( t.tokens, (i + 1) * sizeof(char *) );
396                 t.tokens[i++] = strdup(token);
397         }
398
399         t.numTokens = i;
400         return t;
401 }
402
403 /*
404         Private function name:  free_tokens
405         Since version:          0.4.9
406         Description:            Function to free tokens allocated by tokenize function
407         Arguments:              @t [tTokenizer]: tokenizer structure previously allocated by tokenize function
408         Returns:                none
409 */
410 void free_tokens(tTokenizer t)
411 {
412         int i;
413
414         for (i = 0; i < t.numTokens; i++)
415                 free(t.tokens[i]);
416 }
417
418 /*
419         Private function name:  resource_change_counter
420         Since version:          0.4.2
421         Description:            Function to increment (inc = 1) / decrement (inc = 0) the resource pointers count including the memory location
422         Arguments:              @type [int]: type of resource (INT_RESOURCE_x defines where x can be { CONNECTION | DOMAIN | NETWORK | NODEDEV | STORAGEPOOL | VOLUME | SNAPSHOT })
423                                 @conn [virConnectPtr]: libvirt connection pointer associated with the resource, NULL for libvirt connection objects
424                                 @mem [pointer]: Pointer to memory location for the resource. Will be converted to appropriate uint for the arch.
425                                 @inc [int/bool]: Increment the counter (1 = add memory location) or decrement the counter (0 = remove memory location) from entries.
426         Returns:                0 on success, -errno otherwise
427 */
428 int resource_change_counter(int type, virConnectPtr conn, void *memp, int inc TSRMLS_DC)
429 {
430         int i;
431         int pos = -1;
432         int binding_resources_count;
433         char tmp[64] = { 0 };
434         arch_uint mem = 0;
435         resource_info *binding_resources = NULL;
436
437         snprintf(tmp, sizeof(tmp), "%p", memp);
438         sscanf(tmp, "%"UINTx, &mem);
439
440         binding_resources_count = LIBVIRT_G(binding_resources_count);
441         binding_resources = LIBVIRT_G(binding_resources);
442
443         if (inc) {
444                 for (i = 0; i < binding_resources_count; i++) {
445                         if (binding_resources[i].overwrite) {
446                                 pos = i;
447                                 break;
448                         }
449                         if (pos > -1)
450                                 DPRINTF("%s: Found match on position %d\n", __FUNCTION__, pos);
451                         if ((binding_resources[i].type == type) && (binding_resources[i].mem == mem)
452                                 && (binding_resources[i].overwrite == 0)) {
453                                 DPRINTF("%s: Pointer exists at position %d\n", __FUNCTION__, i);
454                                 return -EEXIST;
455                         }
456                 }
457
458                 if (pos == -1) {
459                         if (binding_resources == NULL) {
460                                 binding_resources_count = 1;
461                                 binding_resources = (resource_info *)malloc( sizeof(resource_info) );
462                         }
463                         else {
464                                 binding_resources_count++;
465                                 binding_resources = (resource_info *)realloc( binding_resources, binding_resources_count * sizeof(resource_info) );
466                         }
467
468                         if (binding_resources == NULL)
469                                 return -ENOMEM;
470
471                         pos = binding_resources_count - 1;
472                 }
473
474                 binding_resources[pos].type = type;
475                 binding_resources[pos].mem  = mem;
476                 binding_resources[pos].conn = conn;
477                 binding_resources[pos].overwrite = 0;
478         }
479         else {
480                 for (i = 0; i < binding_resources_count; i++) {
481                         if ((binding_resources[i].type == type) && (binding_resources[i].mem == mem))
482                                 binding_resources[i].overwrite = 1;
483                 }
484         }
485
486         LIBVIRT_G(binding_resources_count) = binding_resources_count;
487         LIBVIRT_G(binding_resources) = binding_resources;
488
489         return 0;
490 }
491
492 /*
493         Private function name:  get_feature_binary
494         Since version:          0.4.1(-3)
495         Description:            Function to get the existing feature binary for the specified feature, e.g. screenshot feature
496         Arguments:              @name [string]: name of the feature to check against
497         Returns:                Existing and executable binary name or NULL value
498 */
499 char *get_feature_binary(char *name)
500 {
501         int i, max;
502
503         max = (ARRAY_CARDINALITY(features) < ARRAY_CARDINALITY(features_binaries)) ?
504                 ARRAY_CARDINALITY(features) : ARRAY_CARDINALITY(features_binaries);
505
506         for (i = 0; i < max; i++)
507                 if ((features[i] != NULL) && (strcmp(features[i], name) == 0)) {
508                         if (access(features_binaries[i], X_OK) == 0)
509                                 return strdup(features_binaries[i]);
510                 }
511
512         return NULL;
513 }
514
515 /*
516         Private function name:  has_builtin
517         Since version:          0.4.5
518         Description:            Function to get the information whether feature could be used as a built-in feature or not
519         Arguments:              @name [string]: name of the feature to check against
520         Returns:                1 if feature has a builtin fallback to be used or 0 otherwise
521 */
522 int has_builtin(char *name)
523 {
524         int i, max;
525
526         max = (ARRAY_CARDINALITY(features) < ARRAY_CARDINALITY(features_binaries)) ?
527                 ARRAY_CARDINALITY(features) : ARRAY_CARDINALITY(features_binaries);
528
529         for (i = 0; i < max; i++)
530                 if ((features[i] != NULL) && (strcmp(features[i], name) == 0))
531                         return 1;
532
533         return 0;
534 }
535
536 /* Information function for phpinfo() */
537 PHP_MINFO_FUNCTION(libvirt)
538 {
539         int i;
540         char path[1024];
541         char tmp[1024] = { 0 };
542         unsigned long libVer;
543         php_info_print_table_start();
544         php_info_print_table_row(2, "Libvirt support", "enabled");
545
546         #ifdef DEBUG_SUPPORT
547                 snprintf(tmp, sizeof(tmp), "enabled, default maximum log file size: %d KiB", DEFAULT_LOG_MAXSIZE);
548         #else
549                 snprintf(tmp, sizeof(tmp), "disabled");
550         #endif
551
552         php_info_print_table_row(2, "Debug support", tmp);
553         php_info_print_table_row(2, "Extension version", PHP_LIBVIRT_WORLD_VERSION);
554
555         if (virGetVersion(&libVer,NULL,NULL)== 0)
556         {
557                 char version[100];
558                 snprintf(version, sizeof(version), "%i.%i.%i", (long)((libVer/1000000) % 1000),(long)((libVer/1000) % 1000),(long)(libVer % 1000));
559                 php_info_print_table_row(2, "Libvirt version", version);
560         }
561
562         php_info_print_table_row(2, "Max. connections", LIBVIRT_G(max_connections_ini));
563
564         if (!access(LIBVIRT_G(iso_path_ini), F_OK) == 0)
565                 snprintf(path, sizeof(path), "%s - path is invalid. To set the valid path modify the libvirt.iso_path in your php.ini configuration!",
566                                         LIBVIRT_G(iso_path_ini));
567         else
568                 snprintf(path, sizeof(path), "%s", LIBVIRT_G(iso_path_ini));
569
570         php_info_print_table_row(2, "ISO Image path", path);
571
572         if (!access(LIBVIRT_G(image_path_ini), F_OK) == 0)
573                 snprintf(path, sizeof(path), "%s - path is invalid. To set the valid path modify the libvirt.image_path in your php.ini configuration!",
574                                         LIBVIRT_G(image_path_ini));
575         else
576                 snprintf(path, sizeof(path), "%s", LIBVIRT_G(image_path_ini));
577
578         php_info_print_table_row(2, "Path for images", path);
579
580         /* Iterate all the features supported */
581         char features_supported[4096] = { 0 };
582         for (i = 0; i < ARRAY_CARDINALITY(features); i++) {
583                 char *tmp;
584                 if ((features[i] != NULL) && (tmp = get_feature_binary(features[i]))) {
585                         free(tmp);
586                         strcat(features_supported, features[i]);
587                         strcat(features_supported, ", ");
588                 }
589         }
590
591         if (strlen(features_supported) > 0) {
592                 features_supported[ strlen(features_supported) - 2 ] = 0;
593                 php_info_print_table_row(2, "Features supported", features_supported);
594         }
595
596         php_info_print_table_end();
597 }
598
599 /*
600         Private function name:  set_error
601         Since version:          0.4.1(-1)
602         Description:            This private function is used to set the error string to the library. This string can be obtained by libvirt_get_last_error() from the PHP application.
603         Arguments:              @msg [string]: error message string
604         Returns:                None
605 */
606 void set_error(char *msg TSRMLS_DC)
607 {
608         if (LIBVIRT_G (last_error) != NULL)
609                 efree(LIBVIRT_G (last_error));
610
611         if (msg == NULL) {
612                 LIBVIRT_G (last_error) = NULL;
613                 return;
614         }
615
616         php_error_docref(NULL TSRMLS_CC, E_WARNING,"%s",msg);
617         LIBVIRT_G (last_error)=estrndup(msg,strlen(msg));
618 }
619
620 /*
621         Private function name:  set_vnc_location
622         Since version:          0.4.5
623         Description:            This private function is used to set the VNC location for the newly started installation
624         Arguments:              @msg [string]: vnc location string
625         Returns:                None
626 */
627 void set_vnc_location(char *msg TSRMLS_DC)
628 {
629         if (LIBVIRT_G (vnc_location) != NULL)
630                 efree(LIBVIRT_G (vnc_location));
631
632         if (msg == NULL) {
633                 LIBVIRT_G (vnc_location) = NULL;
634                 return;
635         }
636
637         LIBVIRT_G (vnc_location)=estrndup(msg,strlen(msg));
638
639         DPRINTF("set_vnc_location: VNC server location set to '%s'\n", LIBVIRT_G (vnc_location));
640 }
641
642 /*
643         Private function name:  set_error_if_unset
644         Since version:          0.4.2
645         Description:            Function to set the error only if no other error is set yet
646         Arguments:              @msg [string]: error message string
647         Returns:                None
648 */
649 void set_error_if_unset(char *msg TSRMLS_DC)
650 {
651         if (LIBVIRT_G (last_error) == NULL)
652                 set_error(msg TSRMLS_CC);
653 }
654
655 /*
656         Private function name:  reset_error
657         Since version:          0.4.2
658         Description:            Function to reset the error string set by set_error(). Same as set_error(NULL).
659         Arguments:              None
660         Returns:                None
661 */
662 void reset_error(TSRMLS_D)
663 {
664         set_error(NULL TSRMLS_CC);
665 }
666
667
668 /* Error handler for receiving libvirt errors */
669 static void catch_error(void *userData,
670                            virErrorPtr error)
671 {
672         TSRMLS_FETCH_FROM_CTX(userData);
673         set_error(error->message TSRMLS_CC);
674 }
675
676 /*
677         Private function name:  free_resource
678         Since version:          0.4.2
679         Description:            Function is used to free the the internal libvirt-php resource identified by it's type and memory location
680         Arguments:              @type [int]: type of the resource to be freed, INT_RESOURCE_x where x can be { CONNECTION | DOMAIN | NETWORK | NODEDEV | STORAGEPOOL | VOLUME | SNAPSHOT }
681                                 @mem [uint]: memory location of the resource to be freed
682         Returns:                None
683 */
684 void free_resource(int type, arch_uint mem TSRMLS_DC)
685 {
686         int rv;
687
688         DPRINTF("%s: Freeing libvirt %s resource at 0x%"UINTx"\n", __FUNCTION__, translate_counter_type(type), mem);
689
690         if (type == INT_RESOURCE_DOMAIN) {
691                 rv = virDomainFree( (virDomainPtr)mem );
692                 if (rv != 0) {
693                         DPRINTF("%s: virDomainFree(%p) returned %d (%s)\n", __FUNCTION__, (virDomainPtr)mem, rv, LIBVIRT_G (last_error));
694                         php_error_docref(NULL TSRMLS_CC, E_WARNING,"virDomainFree failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
695                 }
696                 else {
697                         DPRINTF("%s: virDomainFree(%p) completed successfully\n", __FUNCTION__, (virDomainPtr)mem);
698                         resource_change_counter(INT_RESOURCE_DOMAIN, NULL, (virDomainPtr)mem, 0 TSRMLS_CC);
699                 }
700         }
701
702         if (type == INT_RESOURCE_NETWORK) {
703                 rv = virNetworkFree( (virNetworkPtr)mem );
704                 if (rv != 0) {
705                         DPRINTF("%s: virNetworkFree(%p) returned %d (%s)\n", __FUNCTION__, (virNetworkPtr)mem, rv, LIBVIRT_G (last_error));
706                         php_error_docref(NULL TSRMLS_CC, E_WARNING,"virNetworkFree failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
707                 }
708                 else {
709                         DPRINTF("%s: virNetworkFree(%p) completed successfully\n", __FUNCTION__, (virNetworkPtr)mem);
710                         resource_change_counter(INT_RESOURCE_NETWORK, NULL, (virNetworkPtr)mem, 0 TSRMLS_CC);
711                 }
712         }
713
714         if (type == INT_RESOURCE_NODEDEV) {
715                 rv = virNodeDeviceFree( (virNodeDevicePtr)mem );
716                 if (rv != 0) {
717                         DPRINTF("%s: virNodeDeviceFree(%p) returned %d (%s)\n", __FUNCTION__, (virNodeDevicePtr)mem, rv, LIBVIRT_G (last_error));
718                         php_error_docref(NULL TSRMLS_CC, E_WARNING,"virNodeDeviceFree failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
719                 }
720                 else {
721                         DPRINTF("%s: virNodeDeviceFree(%p) completed successfully\n", __FUNCTION__, (virNodeDevicePtr)mem);
722                         resource_change_counter(INT_RESOURCE_NODEDEV, NULL, (virNodeDevicePtr)mem, 0 TSRMLS_CC);
723                 }
724         }
725
726         if (type == INT_RESOURCE_STORAGEPOOL) {
727                 rv = virStoragePoolFree( (virStoragePoolPtr)mem );
728                 if (rv != 0) {
729                         DPRINTF("%s: virStoragePoolFree(%p) returned %d (%s)\n", __FUNCTION__, (virStoragePoolPtr)mem, rv, LIBVIRT_G (last_error));
730                         php_error_docref(NULL TSRMLS_CC, E_WARNING,"virStoragePoolFree failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
731                 }
732                 else {
733                         DPRINTF("%s: virStoragePoolFree(%p) completed successfully\n", __FUNCTION__, (virStoragePoolPtr)mem);
734                         resource_change_counter(INT_RESOURCE_STORAGEPOOL, NULL, (virStoragePoolPtr)mem, 0 TSRMLS_CC);
735                 }
736         }
737
738         if (type == INT_RESOURCE_VOLUME) {
739                 rv = virStorageVolFree( (virStorageVolPtr)mem );
740                 if (rv != 0) {
741                         DPRINTF("%s: virStorageVolFree(%p) returned %d (%s)\n", __FUNCTION__, (virStorageVolPtr)mem, rv, LIBVIRT_G (last_error));
742                         php_error_docref(NULL TSRMLS_CC, E_WARNING,"virStorageVolFree failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
743                 }
744                 else {
745                         DPRINTF("%s: virStorageVolFree(%p) completed successfully\n", __FUNCTION__, (virStorageVolPtr)mem);
746                         resource_change_counter(INT_RESOURCE_VOLUME, NULL, (virStorageVolPtr)mem, 0 TSRMLS_CC);
747                 }
748         }
749
750 #if LIBVIR_VERSION_NUMBER>=8000
751         if (type == INT_RESOURCE_SNAPSHOT) {
752                 rv = virDomainSnapshotFree( (virDomainSnapshotPtr)mem );
753                 if (rv != 0) {
754                         DPRINTF("%s: virDomainSnapshotFree(%p) returned %d (%s)\n", __FUNCTION__, (virDomainSnapshotPtr)mem, rv, LIBVIRT_G (last_error));
755                         php_error_docref(NULL TSRMLS_CC, E_WARNING,"virDomainSnapshotFree failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
756                 }
757                 else {
758                         DPRINTF("%s: virDomainSnapshotFree(%p) completed successfully\n", __FUNCTION__, (virDomainSnapshotPtr)mem);
759                         resource_change_counter(INT_RESOURCE_SNAPSHOT, NULL, (virDomainSnapshotPtr)mem, 0 TSRMLS_CC);
760                 }
761         }
762 #endif
763 }
764
765 /*
766         Private function name:  free_resources_on_connection
767         Since version:          0.4.2
768         Description:            Function is used to free all the resources assigned to the connection identified by conn
769         Arguments:              @conn [virConnectPtr]: libvirt connection pointer
770         Returns:                None
771 */
772 void free_resources_on_connection(virConnectPtr conn TSRMLS_DC)
773 {
774         int binding_resources_count = 0;
775         resource_info *binding_resources;
776         int i;
777
778         binding_resources_count = LIBVIRT_G(binding_resources_count);
779         binding_resources = LIBVIRT_G(binding_resources);
780
781         for (i = 0; i < binding_resources_count; i++) {
782                 if ((binding_resources[i].overwrite == 0) && (binding_resources[i].conn == conn))
783                         free_resource(binding_resources[i].type, binding_resources[i].mem TSRMLS_CC);
784         }
785 }
786
787 /*
788         Private function name:  check_resource_allocation
789         Since version:          0.4.2
790         Description:            Function is used to check whether the resource identified by type and memory is allocated for connection conn or not
791         Arguments:              @conn [virConnectPtr]: libvirt connection pointer
792                                 @type [int]: type of the counter to be checked, please see free_resource() API for possible values
793                                 @memp [pointer]: pointer to the memory
794         Returns:                1 if resource is allocated, 0 otherwise
795 */
796 int check_resource_allocation(virConnectPtr conn, int type, void *memp TSRMLS_DC)
797 {
798         int binding_resources_count = 0;
799         resource_info *binding_resources = NULL;
800         int i, allocated = 0;
801         char tmp[64] = { 0 };
802         arch_uint mem = 0;
803
804         snprintf(tmp, sizeof(tmp), "%p", memp);
805         sscanf(tmp, "%"UINTx, &mem);
806
807         binding_resources_count = LIBVIRT_G(binding_resources_count);
808         binding_resources = LIBVIRT_G(binding_resources);
809
810         if (binding_resources == NULL)
811                 return 0;
812
813         for (i = 0; i < binding_resources_count; i++) {
814                 if ((((conn != NULL) && (binding_resources[i].conn == conn)) || (conn == NULL))
815                         && (binding_resources[i].type == type) && (binding_resources[i].mem == mem)
816                         && (binding_resources[i].overwrite == 0))
817                                 allocated = 1;
818         }
819
820         DPRINTF("%s: libvirt %s resource 0x%"UINTx" (conn %p) is%s allocated\n", __FUNCTION__, translate_counter_type(type),
821                 mem, conn, !allocated ? " not" : "");
822         return allocated;
823 }
824
825 /*
826         Private function name:  count_resources
827         Since version:          0.4.2
828         Description:            Function counts the internal resources of module instance
829         Arguments:              @type [int]: integer interpretation of the type, see free_resource() API function for possible values
830         Returns:                number of resources already used
831 */
832 int count_resources(int type TSRMLS_DC)
833 {
834         int binding_resources_count = 0;
835         resource_info *binding_resources = NULL;
836         int i, count = 0;
837
838         binding_resources_count = LIBVIRT_G(binding_resources_count);
839         binding_resources = LIBVIRT_G(binding_resources);
840
841         if (binding_resources == NULL)
842                 return 0;
843
844         for (i = 0; i < binding_resources_count; i++) {
845                 if (binding_resources[i].type == type)
846                         count++;
847         }
848
849         return count;
850 }
851
852 /*
853         Private function name:  size_def_to_mbytes
854         Since version:          0.4.5
855         Description:            Function is used to translate the string size representation to the number of MBytes, used e.g. for domain installation
856         Arguments:              @arg [string]: input string to be converted
857         Returns:                number of megabytes extracted from the input string
858 */
859 unsigned long long size_def_to_mbytes(char *arg)
860 {
861         int unit, multiplicator = 1, nodel = 0;
862
863         if ((arg == NULL) || (strlen(arg) == 0))
864                 return 0;
865
866         unit = arg[strlen(arg)-1];
867         switch (unit) {
868                 case 'G':
869                         multiplicator = 1 << 10;
870                         break;
871                 case 'T':
872                         multiplicator = 1 << 20;
873                         break;
874                 default:
875                         nodel = 1;
876         }
877
878         if (nodel == 0)
879                 arg[strlen(arg) - 1] = 0;
880
881         return atoi(arg) * multiplicator;
882 }
883
884 /*
885         Private function name:  is_local_connection
886         Since version:          0.4.5
887         Description:            Function is used to check whether the connection is the connection to the local hypervisor or to remote hypervisor
888         Arguments:              @conn [virConnectPtr]: libvirt connection pointer
889         Returns:                TRUE for local connection, FALSE for remote connection
890 */
891 int is_local_connection(virConnectPtr conn)
892 {
893         char *hostname;
894         char name[1024];
895
896         hostname=virConnectGetHostname(conn);
897         gethostname(name, 1024);
898         return (strcmp(name, hostname) == 0);
899 }
900
901 /* Destructor for connection resource */
902 static void php_libvirt_connection_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
903 {
904         php_libvirt_connection *conn = (php_libvirt_connection*)rsrc->ptr;
905         int rv = 0;
906
907         if (conn != NULL)
908         {
909                 if (conn->conn != NULL)
910                 {
911                         free_resources_on_connection(conn->conn TSRMLS_CC);
912
913                         rv = virConnectClose(conn->conn);
914                         if (rv == -1) {
915                                 DPRINTF("%s: virConnectClose(%p) returned %d (%s)\n", __FUNCTION__, conn->conn, rv, LIBVIRT_G (last_error));
916                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,"virConnectClose failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
917                         }
918                         else {
919                                 DPRINTF("%s: virConnectClose(%p) completed successfully\n", __FUNCTION__, conn->conn);
920                                 resource_change_counter(INT_RESOURCE_CONNECTION, NULL, conn->conn, 0 TSRMLS_CC);
921                         }
922                         conn->conn=NULL;
923                 }
924                 efree (conn);
925         }
926 }
927
928 /* Destructor for domain resource */
929 static void php_libvirt_domain_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
930 {
931         php_libvirt_domain *domain = (php_libvirt_domain*)rsrc->ptr;
932         int rv = 0;
933
934         if (domain != NULL)
935         {
936                 if (domain->domain != NULL)
937                 {
938                         if (!check_resource_allocation(domain->conn->conn, INT_RESOURCE_DOMAIN, domain->domain TSRMLS_CC)) {
939                                 domain->domain=NULL;
940                                 efree (domain);
941                                 return;
942                         }
943
944                         rv = virDomainFree(domain->domain);
945                         if (rv != 0) {
946                                 DPRINTF("%s: virDomainFree(%p) returned %d (%s)\n", __FUNCTION__, domain->domain, rv, LIBVIRT_G (last_error));
947                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,"virDomainFree failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
948                         }
949                         else {
950                                 DPRINTF("%s: virDomainFree(%p) completed successfully\n", __FUNCTION__, domain->domain);
951                                 resource_change_counter(INT_RESOURCE_DOMAIN, domain->conn->conn, domain->domain, 0 TSRMLS_CC);
952                         }
953                         domain->domain=NULL;
954                 }
955                 efree (domain);
956         }
957 }
958
959 /* Destructor for storagepool resource */
960 static void php_libvirt_storagepool_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
961 {
962         php_libvirt_storagepool *pool = (php_libvirt_storagepool*)rsrc->ptr;
963         int rv = 0;
964
965         if (pool != NULL)
966         {
967                 if (pool->pool != NULL)
968                 {
969                         if (!check_resource_allocation(NULL, INT_RESOURCE_STORAGEPOOL, pool->pool TSRMLS_CC)) {
970                                 pool->pool=NULL;
971                                 efree(pool);
972                                 return;
973                         }
974                         rv = virStoragePoolFree(pool->pool);
975                         if (rv!=0) {
976                                 DPRINTF("%s: virStoragePoolFree(%p) returned %d (%s)\n", __FUNCTION__, pool->pool, rv, LIBVIRT_G (last_error));
977                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,"virStoragePoolFree failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
978                         }
979                         else {
980                                 DPRINTF("%s: virStoragePoolFree(%p) completed successfully\n", __FUNCTION__, pool->pool);
981                                 resource_change_counter(INT_RESOURCE_STORAGEPOOL, NULL, pool->pool, 0 TSRMLS_CC);
982                         }
983                         pool->pool=NULL;
984                 }
985                 efree(pool);
986         }
987 }
988
989 /* Destructor for volume resource */
990 static void php_libvirt_volume_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
991 {
992         php_libvirt_volume *volume = (php_libvirt_volume*)rsrc->ptr;
993         int rv = 0;
994
995         if (volume != NULL)
996         {
997                 if (volume->volume != NULL)
998                 {
999                         if (!check_resource_allocation(NULL, INT_RESOURCE_VOLUME, volume->volume TSRMLS_CC)) {
1000                                 volume->volume=NULL;
1001                                 efree(volume);
1002                                 return;
1003                         }
1004                         rv = virStorageVolFree (volume->volume);
1005                         if (rv!=0) {
1006                                 DPRINTF("%s: virStorageVolFree(%p) returned %d (%s)\n", __FUNCTION__, volume->volume, rv, LIBVIRT_G (last_error));
1007                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,"virStorageVolFree failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
1008                         }
1009                         else {
1010                                 DPRINTF("%s: virStorageVolFree(%p) completed successfully\n", __FUNCTION__, volume->volume);
1011                                 resource_change_counter(INT_RESOURCE_VOLUME, NULL, volume->volume, 0 TSRMLS_CC);
1012                         }
1013                         volume->volume=NULL;
1014                 }
1015                 efree(volume);
1016         }
1017 }
1018
1019 /* Destructor for network resource */
1020 static void php_libvirt_network_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
1021 {
1022         php_libvirt_network *network = (php_libvirt_network*)rsrc->ptr;
1023         int rv = 0;
1024
1025         if (network != NULL)
1026         {
1027                 if (network->network != NULL)
1028                 {
1029                         if (!check_resource_allocation(network->conn->conn, INT_RESOURCE_NETWORK, network->network TSRMLS_CC)) {
1030                                 network->network=NULL;
1031                                 efree(network);
1032                                 return;
1033                         }
1034                         rv = virNetworkFree(network->network);
1035                         if (rv!=0) {
1036                                 DPRINTF("%s: virNetworkFree(%p) returned %d (%s)\n", __FUNCTION__, network->network, rv, LIBVIRT_G (last_error));
1037                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,"virStorageVolFree failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
1038                         }
1039                         else {
1040                                 DPRINTF("%s: virNetworkFree(%p) completed successfully\n", __FUNCTION__, network->network);
1041                                 resource_change_counter(INT_RESOURCE_NETWORK, NULL, network->network, 0 TSRMLS_CC);
1042                         }
1043                         network->network=NULL;
1044                 }
1045                 efree(network);
1046         }
1047 }
1048
1049 /* Destructor for nodedev resource */
1050 static void php_libvirt_nodedev_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
1051 {
1052         php_libvirt_nodedev *nodedev = (php_libvirt_nodedev*)rsrc->ptr;
1053         int rv = 0;
1054
1055         if (nodedev != NULL)
1056         {
1057                 if (nodedev->device != NULL)
1058                 {
1059                         if (!check_resource_allocation(nodedev->conn->conn, INT_RESOURCE_NODEDEV, nodedev->device TSRMLS_CC)) {
1060                                 nodedev->device=NULL;
1061                                 efree(nodedev);
1062                                 return;
1063                         }
1064                         rv = virNodeDeviceFree(nodedev->device);
1065                         if (rv!=0) {
1066                                 DPRINTF("%s: virNodeDeviceFree(%p) returned %d (%s)\n", __FUNCTION__, nodedev->device, rv, LIBVIRT_G (last_error));
1067                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,"virStorageVolFree failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
1068                         }
1069                         else {
1070                                 DPRINTF("%s: virNodeDeviceFree(%p) completed successfully\n", __FUNCTION__, nodedev->device);
1071                                 resource_change_counter(INT_RESOURCE_NODEDEV, nodedev->conn->conn, nodedev->device, 0 TSRMLS_CC);
1072                         }
1073                         nodedev->device=NULL;
1074                 }
1075                 efree(nodedev);
1076         }
1077 }
1078
1079 #if LIBVIR_VERSION_NUMBER>=8000
1080 /* Destructor for snapshot resource */
1081 static void php_libvirt_snapshot_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
1082 {
1083         php_libvirt_snapshot *snapshot = (php_libvirt_snapshot*)rsrc->ptr;
1084         int rv = 0;
1085
1086         if (snapshot != NULL)
1087         {
1088                 if (snapshot->snapshot != NULL)
1089                 {
1090                         if (!check_resource_allocation(NULL, INT_RESOURCE_SNAPSHOT, snapshot->snapshot TSRMLS_CC)) {
1091                                 snapshot->snapshot=NULL;
1092                                 efree(snapshot);
1093                                 return;
1094                         }
1095                         rv = virDomainSnapshotFree(snapshot->snapshot);
1096                         if (rv!=0) {
1097                                 DPRINTF("%s: virDomainSnapshotFree(%p) returned %d\n", __FUNCTION__, snapshot->snapshot, rv);
1098                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,"virStorageVolFree failed with %i on destructor: %s", rv, LIBVIRT_G (last_error));
1099                         }
1100                         else {
1101                                 DPRINTF("%s: virDomainSnapshotFree(%p) completed successfully\n", __FUNCTION__, snapshot->snapshot);
1102                                 resource_change_counter(INT_RESOURCE_SNAPSHOT, snapshot->domain->conn->conn, snapshot->snapshot, 0 TSRMLS_CC);
1103                         }
1104                         snapshot->snapshot=NULL;
1105                 }
1106                 efree(snapshot);
1107         }
1108 }
1109 #endif
1110
1111 /* ZEND Module inicialization function */
1112 PHP_MINIT_FUNCTION(libvirt)
1113 {
1114         /* register resource types and their descriptors */
1115         le_libvirt_connection = zend_register_list_destructors_ex(php_libvirt_connection_dtor, NULL, PHP_LIBVIRT_CONNECTION_RES_NAME, module_number);
1116         le_libvirt_domain = zend_register_list_destructors_ex(php_libvirt_domain_dtor, NULL, PHP_LIBVIRT_DOMAIN_RES_NAME, module_number);
1117         le_libvirt_storagepool = zend_register_list_destructors_ex(php_libvirt_storagepool_dtor, NULL, PHP_LIBVIRT_STORAGEPOOL_RES_NAME, module_number);
1118         le_libvirt_volume = zend_register_list_destructors_ex(php_libvirt_volume_dtor, NULL, PHP_LIBVIRT_VOLUME_RES_NAME, module_number);
1119         le_libvirt_network = zend_register_list_destructors_ex(php_libvirt_network_dtor, NULL, PHP_LIBVIRT_NETWORK_RES_NAME, module_number);
1120         le_libvirt_nodedev = zend_register_list_destructors_ex(php_libvirt_nodedev_dtor, NULL, PHP_LIBVIRT_NODEDEV_RES_NAME, module_number);
1121         #if LIBVIR_VERSION_NUMBER>=8000
1122         le_libvirt_snapshot = zend_register_list_destructors_ex(php_libvirt_snapshot_dtor, NULL, PHP_LIBVIRT_SNAPSHOT_RES_NAME, module_number);
1123         #endif
1124
1125         ZEND_INIT_MODULE_GLOBALS(libvirt, php_libvirt_init_globals, NULL);
1126
1127         /* LIBVIRT CONSTANTS */
1128
1129         /* XML contants */
1130         REGISTER_LONG_CONSTANT("VIR_DOMAIN_XML_SECURE",         1, CONST_CS | CONST_PERSISTENT);
1131         REGISTER_LONG_CONSTANT("VIR_DOMAIN_XML_INACTIVE",       2, CONST_CS | CONST_PERSISTENT);
1132
1133         REGISTER_LONG_CONSTANT("VIR_NODE_CPU_STATS_ALL_CPUS",   VIR_NODE_CPU_STATS_ALL_CPUS, CONST_CS | CONST_PERSISTENT);
1134
1135         /* Domain constants */
1136         REGISTER_LONG_CONSTANT("VIR_DOMAIN_NOSTATE",            0, CONST_CS | CONST_PERSISTENT);
1137         REGISTER_LONG_CONSTANT("VIR_DOMAIN_RUNNING",            1, CONST_CS | CONST_PERSISTENT);
1138         REGISTER_LONG_CONSTANT("VIR_DOMAIN_BLOCKED",            2, CONST_CS | CONST_PERSISTENT);
1139         REGISTER_LONG_CONSTANT("VIR_DOMAIN_PAUSED",             3, CONST_CS | CONST_PERSISTENT);
1140         REGISTER_LONG_CONSTANT("VIR_DOMAIN_SHUTDOWN",           4, CONST_CS | CONST_PERSISTENT);
1141         REGISTER_LONG_CONSTANT("VIR_DOMAIN_SHUTOFF",            5, CONST_CS | CONST_PERSISTENT);
1142         REGISTER_LONG_CONSTANT("VIR_DOMAIN_CRASHED",            6, CONST_CS | CONST_PERSISTENT);
1143
1144         /* Domain vCPU flags */
1145         REGISTER_LONG_CONSTANT("VIR_DOMAIN_VCPU_CONFIG",        VIR_DOMAIN_VCPU_CONFIG, CONST_CS | CONST_PERSISTENT);
1146         REGISTER_LONG_CONSTANT("VIR_DOMAIN_VCPU_CURRENT",       VIR_DOMAIN_VCPU_CURRENT, CONST_CS | CONST_PERSISTENT);
1147         REGISTER_LONG_CONSTANT("VIR_DOMAIN_VCPU_LIVE",          VIR_DOMAIN_VCPU_LIVE, CONST_CS | CONST_PERSISTENT);
1148         REGISTER_LONG_CONSTANT("VIR_DOMAIN_VCPU_MAXIMUM",       VIR_DOMAIN_VCPU_MAXIMUM, CONST_CS | CONST_PERSISTENT);
1149         REGISTER_LONG_CONSTANT("VIR_DOMAIN_VCPU_GUEST",         VIR_DOMAIN_VCPU_GUEST, CONST_CS | CONST_PERSISTENT);
1150
1151         #if LIBVIR_VERSION_NUMBER>=8000
1152         /* Domain snapshot constants */
1153         REGISTER_LONG_CONSTANT("VIR_SNAPSHOT_DELETE_CHILDREN",   VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN,   CONST_CS | CONST_PERSISTENT);
1154         #endif
1155
1156         /* Memory constants */
1157         REGISTER_LONG_CONSTANT("VIR_MEMORY_VIRTUAL",            1, CONST_CS | CONST_PERSISTENT);
1158
1159         /* Version checking constants */
1160         REGISTER_LONG_CONSTANT("VIR_VERSION_BINDING",           VIR_VERSION_BINDING,    CONST_CS | CONST_PERSISTENT);
1161         REGISTER_LONG_CONSTANT("VIR_VERSION_LIBVIRT",           VIR_VERSION_LIBVIRT,    CONST_CS | CONST_PERSISTENT);
1162
1163         /* Network constants */
1164         REGISTER_LONG_CONSTANT("VIR_NETWORKS_ACTIVE",           VIR_NETWORKS_ACTIVE,    CONST_CS | CONST_PERSISTENT);
1165         REGISTER_LONG_CONSTANT("VIR_NETWORKS_INACTIVE",         VIR_NETWORKS_INACTIVE,  CONST_CS | CONST_PERSISTENT);
1166         REGISTER_LONG_CONSTANT("VIR_NETWORKS_ALL",              VIR_NETWORKS_ACTIVE |
1167                                                                 VIR_NETWORKS_INACTIVE,  CONST_CS | CONST_PERSISTENT);
1168
1169         /* Credential constants */
1170         REGISTER_LONG_CONSTANT("VIR_CRED_USERNAME",             1, CONST_CS | CONST_PERSISTENT);
1171         REGISTER_LONG_CONSTANT("VIR_CRED_AUTHNAME",             2, CONST_CS | CONST_PERSISTENT);
1172         /* RFC 1766 languages */
1173         REGISTER_LONG_CONSTANT("VIR_CRED_LANGUAGE",             3, CONST_CS | CONST_PERSISTENT);
1174         /* Client supplied a nonce */
1175         REGISTER_LONG_CONSTANT("VIR_CRED_CNONCE",               4, CONST_CS | CONST_PERSISTENT);
1176         /* Passphrase secret */
1177         REGISTER_LONG_CONSTANT("VIR_CRED_PASSPHRASE",           5, CONST_CS | CONST_PERSISTENT);
1178         /* Challenge response */
1179         REGISTER_LONG_CONSTANT("VIR_CRED_ECHOPROMPT",           6, CONST_CS | CONST_PERSISTENT);
1180         /* Challenge responce */
1181         REGISTER_LONG_CONSTANT("VIR_CRED_NOECHOPROMP",          7, CONST_CS | CONST_PERSISTENT);
1182         /* Authentication realm */
1183         REGISTER_LONG_CONSTANT("VIR_CRED_REALM",                8, CONST_CS | CONST_PERSISTENT);
1184         /* Externally managed credential More may be added - expect the unexpected */
1185         REGISTER_LONG_CONSTANT("VIR_CRED_EXTERNAL",             9, CONST_CS | CONST_PERSISTENT);
1186
1187         /* Domain memory constants */
1188         /* The total amount of memory written out to swap space (in kB). */
1189         REGISTER_LONG_CONSTANT("VIR_DOMAIN_MEMORY_STAT_SWAP_IN",        0, CONST_CS | CONST_PERSISTENT);
1190         /*  Page faults occur when a process makes a valid access to virtual memory that is not available. */
1191         /* When servicing the page fault, if disk IO is * required, it is considered a major fault. If not, */
1192         /* it is a minor fault. * These are expressed as the number of faults that have occurred. */
1193         REGISTER_LONG_CONSTANT("VIR_DOMAIN_MEMORY_STAT_SWAP_OUT",       1, CONST_CS | CONST_PERSISTENT);
1194         REGISTER_LONG_CONSTANT("VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT",    2, CONST_CS | CONST_PERSISTENT);
1195         /* The amount of memory left completely unused by the system. Memory that is available but used for */
1196         /* reclaimable caches should NOT be reported as free. This value is expressed in kB. */
1197         REGISTER_LONG_CONSTANT("VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT",    3, CONST_CS | CONST_PERSISTENT);
1198         /* The total amount of usable memory as seen by the domain. This value * may be less than the amount */
1199         /* of memory assigned to the domain if a * balloon driver is in use or if the guest OS does not initialize */
1200         /* all * assigned pages. This value is expressed in kB.  */
1201         REGISTER_LONG_CONSTANT("VIR_DOMAIN_MEMORY_STAT_UNUSED",         4, CONST_CS | CONST_PERSISTENT);
1202         /* The number of statistics supported by this version of the interface. To add new statistics, add them */
1203         /* to the enum and increase this value. */
1204         REGISTER_LONG_CONSTANT("VIR_DOMAIN_MEMORY_STAT_AVAILABLE",      5, CONST_CS | CONST_PERSISTENT);
1205         REGISTER_LONG_CONSTANT("VIR_DOMAIN_MEMORY_STAT_NR",             6, CONST_CS | CONST_PERSISTENT);
1206
1207         /* Job constants */
1208         REGISTER_LONG_CONSTANT("VIR_DOMAIN_JOB_NONE",           0, CONST_CS | CONST_PERSISTENT);
1209         /* Job with a finite completion time */
1210         REGISTER_LONG_CONSTANT("VIR_DOMAIN_JOB_BOUNDED",        1, CONST_CS | CONST_PERSISTENT);
1211         /* Job without a finite completion time */
1212         REGISTER_LONG_CONSTANT("VIR_DOMAIN_JOB_UNBOUNDED",      2, CONST_CS | CONST_PERSISTENT);
1213         /* Job has finished but it's not cleaned up yet */
1214         REGISTER_LONG_CONSTANT("VIR_DOMAIN_JOB_COMPLETED",      3, CONST_CS | CONST_PERSISTENT);
1215         /* Job hit error but it's not cleaned up yet */
1216         REGISTER_LONG_CONSTANT("VIR_DOMAIN_JOB_FAILED",         4, CONST_CS | CONST_PERSISTENT);
1217         /* Job was aborted but it's not cleanup up yet */
1218         REGISTER_LONG_CONSTANT("VIR_DOMAIN_JOB_CANCELLED",      5, CONST_CS | CONST_PERSISTENT);
1219
1220         /* Migration constants */
1221         REGISTER_LONG_CONSTANT("VIR_MIGRATE_LIVE",                1, CONST_CS | CONST_PERSISTENT);
1222         /* direct source -> dest host control channel Note the less-common spelling that we're stuck with: */
1223         /* VIR_MIGRATE_TUNNELLED should be VIR_MIGRATE_TUNNELED */
1224         REGISTER_LONG_CONSTANT("VIR_MIGRATE_PEER2PEER",           2, CONST_CS | CONST_PERSISTENT);
1225         /* tunnel migration data over libvirtd connection */
1226         REGISTER_LONG_CONSTANT("VIR_MIGRATE_TUNNELLED",           4, CONST_CS | CONST_PERSISTENT);
1227         /* persist the VM on the destination */
1228         REGISTER_LONG_CONSTANT("VIR_MIGRATE_PERSIST_DEST",        8, CONST_CS | CONST_PERSISTENT);
1229         /* undefine the VM on the source */
1230         REGISTER_LONG_CONSTANT("VIR_MIGRATE_UNDEFINE_SOURCE",    16, CONST_CS | CONST_PERSISTENT);
1231         /* pause on remote side */
1232         REGISTER_LONG_CONSTANT("VIR_MIGRATE_PAUSED",             32, CONST_CS | CONST_PERSISTENT);
1233         /* migration with non-shared storage with full disk copy */
1234         REGISTER_LONG_CONSTANT("VIR_MIGRATE_NON_SHARED_DISK",    64, CONST_CS | CONST_PERSISTENT);
1235         /* migration with non-shared storage with incremental copy (same base image shared between source and destination) */
1236         REGISTER_LONG_CONSTANT("VIR_MIGRATE_NON_SHARED_INC",    128, CONST_CS | CONST_PERSISTENT);
1237
1238     /* Modify device allocation based on current domain state */
1239         REGISTER_LONG_CONSTANT("VIR_DOMAIN_DEVICE_MODIFY_CURRENT",      0, CONST_CS | CONST_PERSISTENT);
1240         /* Modify live device allocation */
1241         REGISTER_LONG_CONSTANT("VIR_DOMAIN_DEVICE_MODIFY_LIVE",         1, CONST_CS | CONST_PERSISTENT);
1242         /* Modify persisted device allocation */
1243         REGISTER_LONG_CONSTANT("VIR_DOMAIN_DEVICE_MODIFY_CONFIG",       2, CONST_CS | CONST_PERSISTENT);
1244         /* Forcibly modify device (ex. force eject a cdrom) */
1245         REGISTER_LONG_CONSTANT("VIR_DOMAIN_DEVICE_MODIFY_FORCE",        4, CONST_CS | CONST_PERSISTENT);
1246
1247         /* REGISTER_LONG_CONSTANT */
1248         REGISTER_LONG_CONSTANT("VIR_STORAGE_POOL_BUILD_NEW",            0, CONST_CS | CONST_PERSISTENT);
1249         /* Repair / reinitialize */
1250         REGISTER_LONG_CONSTANT("VIR_STORAGE_POOL_BUILD_REPAIR",         1, CONST_CS | CONST_PERSISTENT);
1251         /* Extend existing pool */
1252         REGISTER_LONG_CONSTANT("VIR_STORAGE_POOL_BUILD_RESIZE",         2, CONST_CS | CONST_PERSISTENT);
1253
1254         /* Domain flags */
1255         REGISTER_LONG_CONSTANT("VIR_DOMAIN_FLAG_FEATURE_ACPI",          DOMAIN_FLAG_FEATURE_ACPI, CONST_CS | CONST_PERSISTENT);
1256         REGISTER_LONG_CONSTANT("VIR_DOMAIN_FLAG_FEATURE_APIC",          DOMAIN_FLAG_FEATURE_APIC, CONST_CS | CONST_PERSISTENT);
1257         REGISTER_LONG_CONSTANT("VIR_DOMAIN_FLAG_FEATURE_PAE",           DOMAIN_FLAG_FEATURE_PAE, CONST_CS | CONST_PERSISTENT);
1258         REGISTER_LONG_CONSTANT("VIR_DOMAIN_FLAG_CLOCK_LOCALTIME",       DOMAIN_FLAG_CLOCK_LOCALTIME, CONST_CS | CONST_PERSISTENT);
1259         REGISTER_LONG_CONSTANT("VIR_DOMAIN_FLAG_TEST_LOCAL_VNC",        DOMAIN_FLAG_TEST_LOCAL_VNC, CONST_CS | CONST_PERSISTENT);
1260         REGISTER_LONG_CONSTANT("VIR_DOMAIN_FLAG_SOUND_AC97",            DOMAIN_FLAG_SOUND_AC97, CONST_CS | CONST_PERSISTENT);
1261         REGISTER_LONG_CONSTANT("VIR_DOMAIN_DISK_FILE",                  DOMAIN_DISK_FILE, CONST_CS | CONST_PERSISTENT);
1262         REGISTER_LONG_CONSTANT("VIR_DOMAIN_DISK_BLOCK",                 DOMAIN_DISK_BLOCK, CONST_CS | CONST_PERSISTENT);
1263         REGISTER_LONG_CONSTANT("VIR_DOMAIN_DISK_ACCESS_ALL",            DOMAIN_DISK_ACCESS_ALL, CONST_CS | CONST_PERSISTENT);
1264
1265         /* Domain metadata constants */
1266         REGISTER_LONG_CONSTANT("VIR_DOMAIN_METADATA_DESCRIPTION",       0, CONST_CS | CONST_PERSISTENT);
1267         REGISTER_LONG_CONSTANT("VIR_DOMAIN_METADATA_TITLE",             1, CONST_CS | CONST_PERSISTENT);
1268         REGISTER_LONG_CONSTANT("VIR_DOMAIN_METADATA_ELEMENT",           2, CONST_CS | CONST_PERSISTENT);
1269         REGISTER_LONG_CONSTANT("VIR_DOMAIN_AFFECT_CURRENT",             0, CONST_CS | CONST_PERSISTENT);
1270         REGISTER_LONG_CONSTANT("VIR_DOMAIN_AFFECT_LIVE",                1, CONST_CS | CONST_PERSISTENT);
1271         REGISTER_LONG_CONSTANT("VIR_DOMAIN_AFFECT_CONFIG",              2, CONST_CS | CONST_PERSISTENT);
1272
1273         /* Connect flags */
1274         REGISTER_LONG_CONSTANT("VIR_CONNECT_FLAG_SOUNDHW_GET_NAMES",    CONNECT_FLAG_SOUNDHW_GET_NAMES, CONST_CS | CONST_PERSISTENT);
1275
1276         REGISTER_INI_ENTRIES();
1277
1278         /* Initialize libvirt and set up error callback */
1279         virInitialize();
1280
1281         void *thread_ctx = NULL;
1282         TSRMLS_SET_CTX(thread_ctx);
1283         virSetErrorFunc(thread_ctx, catch_error);
1284
1285         return SUCCESS;
1286 }
1287
1288 /* Zend module destruction */
1289 PHP_MSHUTDOWN_FUNCTION(libvirt)
1290 {
1291     UNREGISTER_INI_ENTRIES();
1292
1293     /* return error callback back to default (outouts to STDOUT) */
1294     virSetErrorFunc(NULL, NULL);
1295     return SUCCESS;
1296 }
1297
1298 /* Macros for obtaining resources from arguments */
1299 #define GET_CONNECTION_FROM_ARGS(args, ...) \
1300         reset_error(TSRMLS_C);  \
1301         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, args, __VA_ARGS__) == FAILURE) {\
1302                 set_error("Invalid arguments" TSRMLS_CC);       \
1303                 RETURN_FALSE;\
1304         }\
1305 \
1306         ZEND_FETCH_RESOURCE(conn, php_libvirt_connection*, &zconn, -1, PHP_LIBVIRT_CONNECTION_RES_NAME, le_libvirt_connection);\
1307         if ((conn==NULL) || (conn->conn==NULL)) RETURN_FALSE;\
1308
1309 #define GET_DOMAIN_FROM_ARGS(args, ...) \
1310         reset_error(TSRMLS_C);  \
1311         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, args, __VA_ARGS__) == FAILURE) {\
1312                 set_error("Invalid arguments" TSRMLS_CC); \
1313                 RETURN_FALSE;\
1314         }\
1315 \
1316         ZEND_FETCH_RESOURCE(domain, php_libvirt_domain*, &zdomain, -1, PHP_LIBVIRT_DOMAIN_RES_NAME, le_libvirt_domain);\
1317         if ((domain==NULL) || (domain->domain==NULL)) RETURN_FALSE;\
1318
1319 #define GET_NETWORK_FROM_ARGS(args, ...) \
1320         reset_error(TSRMLS_C);  \
1321         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, args, __VA_ARGS__) == FAILURE) {\
1322                 set_error("Invalid arguments" TSRMLS_CC);\
1323                 RETURN_FALSE;\
1324         }\
1325 \
1326         ZEND_FETCH_RESOURCE(network, php_libvirt_network*, &znetwork, -1, PHP_LIBVIRT_NETWORK_RES_NAME, le_libvirt_network);\
1327         if ((network==NULL) || (network->network==NULL)) RETURN_FALSE;\
1328
1329 #define GET_NODEDEV_FROM_ARGS(args, ...) \
1330         reset_error(TSRMLS_C);  \
1331         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, args, __VA_ARGS__) == FAILURE) {\
1332                 set_error("Invalid arguments" TSRMLS_CC);\
1333                 RETURN_FALSE;\
1334         }\
1335 \
1336         ZEND_FETCH_RESOURCE(nodedev, php_libvirt_nodedev*, &znodedev, -1, PHP_LIBVIRT_NODEDEV_RES_NAME, le_libvirt_nodedev);\
1337         if ((nodedev==NULL) || (nodedev->device==NULL)) RETURN_FALSE;\
1338
1339 #define GET_STORAGEPOOL_FROM_ARGS(args, ...) \
1340         reset_error(TSRMLS_C);  \
1341         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, args, __VA_ARGS__) == FAILURE) {\
1342                 set_error("Invalid arguments" TSRMLS_CC);\
1343                 RETURN_FALSE;\
1344         }\
1345 \
1346         ZEND_FETCH_RESOURCE(pool, php_libvirt_storagepool*, &zpool, -1, PHP_LIBVIRT_STORAGEPOOL_RES_NAME, le_libvirt_storagepool);\
1347         if ((pool==NULL) || (pool->pool==NULL)) RETURN_FALSE;\
1348
1349 #define GET_VOLUME_FROM_ARGS(args, ...) \
1350         reset_error(TSRMLS_C);  \
1351         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, args, __VA_ARGS__) == FAILURE) {\
1352                 set_error("Invalid arguments" TSRMLS_CC);\
1353                 RETURN_FALSE;\
1354         }\
1355 \
1356         ZEND_FETCH_RESOURCE(volume, php_libvirt_volume*, &zvolume, -1, PHP_LIBVIRT_VOLUME_RES_NAME, le_libvirt_volume);\
1357         if ((volume==NULL) || (volume->volume==NULL)) RETURN_FALSE;\
1358
1359 #if LIBVIR_VERSION_NUMBER>=8000
1360
1361 #define GET_SNAPSHOT_FROM_ARGS(args, ...) \
1362         reset_error(TSRMLS_C);  \
1363         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, args, __VA_ARGS__) == FAILURE) {\
1364                 set_error("Invalid arguments" TSRMLS_CC);\
1365                 RETURN_FALSE;\
1366         }\
1367 \
1368         ZEND_FETCH_RESOURCE(snapshot, php_libvirt_snapshot*, &zsnapshot, -1, PHP_LIBVIRT_SNAPSHOT_RES_NAME, le_libvirt_snapshot);\
1369         if ((snapshot==NULL) || (snapshot->snapshot==NULL)) RETURN_FALSE;\
1370
1371 #endif
1372
1373 /* Macro to "recreate" string with emalloc and free the original one */
1374 #define RECREATE_STRING_WITH_E(str_out, str_in) \
1375 str_out = estrndup(str_in, strlen(str_in)); \
1376          free(str_in);   \
1377
1378 #define LONGLONG_INIT \
1379         char tmpnumber[64];
1380
1381 #define LONGLONG_ASSOC(out,key,in) \
1382         if (LIBVIRT_G(longlong_to_string_ini)) { \
1383           snprintf(tmpnumber,63,"%llu",in); \
1384           add_assoc_string_ex(out,key,strlen(key)+1,tmpnumber,1); \
1385         } \
1386         else \
1387         { \
1388            add_assoc_long(out,key,in); \
1389         }
1390
1391 #define LONGLONG_INDEX(out,key,in) \
1392         if (LIBVIRT_G(longlong_to_string_ini)) { \
1393           snprintf(tmpnumber,63,"%llu",in); \
1394           add_index_string(out,key,tmpnumber,1); \
1395         } \
1396         else \
1397         { \
1398            add_index_long(out, key,in); \
1399         }
1400
1401 /* Authentication callback function. Should receive list of credentials via cbdata and pass the requested one to libvirt */
1402 static int libvirt_virConnectAuthCallback(virConnectCredentialPtr cred,  unsigned int ncred,  void *cbdata)
1403 {
1404     TSRMLS_FETCH();
1405
1406         int i,j;
1407         php_libvirt_cred_value *creds=(php_libvirt_cred_value*) cbdata;
1408         for(i=0;i<ncred;i++)
1409         {
1410                 DPRINTF("%s: cred %d, type %d, prompt %s challenge %s\n ", __FUNCTION__, i, cred[i].type, cred[i].prompt, cred[i].challenge);
1411                 if (creds != NULL)
1412                         for (j=0;j<creds[0].count;j++)
1413                         {
1414                                 if (creds[j].type==cred[i].type)
1415                                 {
1416                                         cred[i].resultlen=creds[j].resultlen;
1417                                         cred[i].result=malloc(creds[j].resultlen + 1);
1418                                         memset(cred[i].result, 0, creds[j].resultlen + 1);
1419                                         strncpy(cred[i].result,creds[j].result,creds[j].resultlen);
1420                                 }
1421                         }
1422                         DPRINTF("%s: result %s (%d)\n", __FUNCTION__, cred[i].result, cred[i].resultlen);
1423         }
1424
1425         return 0;
1426 }
1427
1428 static int libvirt_virConnectCredType[] = {
1429         VIR_CRED_AUTHNAME,
1430         VIR_CRED_ECHOPROMPT,
1431         VIR_CRED_REALM,
1432         VIR_CRED_PASSPHRASE,
1433         VIR_CRED_NOECHOPROMPT,
1434         //VIR_CRED_EXTERNAL,
1435 };
1436
1437 /* Common functions */
1438
1439 /*
1440         Function name:  libvirt_get_last_error
1441         Since version:  0.4.1(-1)
1442         Description:    This function is used to get the last error coming either from libvirt or the PHP extension itself
1443         Returns:        last error string
1444 */
1445 PHP_FUNCTION(libvirt_get_last_error)
1446 {
1447         if (LIBVIRT_G (last_error) == NULL) RETURN_NULL();
1448         RETURN_STRING(LIBVIRT_G (last_error),1);
1449 }
1450
1451 /*
1452         Function name:  libvirt_connect
1453         Since version:  0.4.1(-1)
1454         Description:    libvirt_connect() is used to connect to the specified libvirt daemon using the specified URL, user can also set the readonly flag and/or set credentials for connection
1455         Arguments:      @url [string]: URI for connection
1456                         @readonly [bool]: flag whether to use read-only connection or not
1457                         @credentials [array]: array of connection credentials
1458         Returns:        libvirt connection resource
1459 */
1460 PHP_FUNCTION(libvirt_connect)
1461 {
1462         php_libvirt_connection *conn;
1463         php_libvirt_cred_value *creds=NULL;
1464         zval* zcreds=NULL;
1465         zval **data;
1466         int i;
1467         int j;
1468         int credscount=0;
1469
1470         virConnectAuth libvirt_virConnectAuth= { libvirt_virConnectCredType, sizeof(libvirt_virConnectCredType)/sizeof(int), libvirt_virConnectAuthCallback, NULL};
1471
1472         char *url=NULL;
1473         int url_len=0;
1474         int readonly=1;
1475
1476         HashTable *arr_hash;
1477         HashPosition pointer;
1478         int array_count;
1479
1480         char *key;
1481         unsigned int key_len;
1482         unsigned long index;
1483
1484         unsigned long libVer;
1485
1486         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sba", &url,&url_len,&readonly,&zcreds) == FAILURE) {
1487                 RETURN_FALSE;
1488         }
1489
1490         if (virGetVersion(&libVer,NULL,NULL)!= 0)
1491                 RETURN_FALSE;
1492
1493         if (libVer<6002)
1494         {
1495                 set_error("Only libvirt 0.6.2 and higher supported. Please upgrade your libvirt" TSRMLS_CC);
1496                 RETURN_FALSE;
1497         }
1498
1499         if ((count_resources(INT_RESOURCE_CONNECTION TSRMLS_CC) + 1) > atoi(LIBVIRT_G(max_connections_ini))) {
1500                 DPRINTF("%s: maximum number of connections allowed exceeded (max %s)\n",PHPFUNC, LIBVIRT_G(max_connections_ini));
1501                 set_error("Maximum number of connections allowed exceeded" TSRMLS_CC);
1502                 RETURN_FALSE;
1503         }
1504
1505         /* If 'null' value has been passed as URL override url to NULL value to autodetect the hypervisor */
1506         if ((url == NULL) || (strcasecmp(url, "NULL") == 0))
1507                 url = NULL;
1508
1509         conn=emalloc(sizeof(php_libvirt_connection));
1510         if (zcreds==NULL)
1511         {       /* connecting without providing authentication */
1512                 if (readonly)
1513                         conn->conn = virConnectOpenReadOnly(url);
1514                 else
1515                         conn->conn = virConnectOpen(url);
1516         }
1517         else
1518         {  /* connecting with authentication (using callback) */
1519                 arr_hash = Z_ARRVAL_P(zcreds);
1520                 array_count = zend_hash_num_elements(arr_hash);
1521
1522                 credscount=array_count;
1523                 creds=emalloc(credscount*sizeof(php_libvirt_cred_value));
1524                 j=0;
1525                 /* parse the input Array and create list of credentials. The list (array) is passed to callback function. */
1526                 for (zend_hash_internal_pointer_reset_ex(arr_hash, &pointer);
1527                         zend_hash_get_current_data_ex(arr_hash, (void**) &data, &pointer) == SUCCESS;
1528                         zend_hash_move_forward_ex(arr_hash, &pointer)) {
1529                                 if (Z_TYPE_PP(data) == IS_STRING) {
1530                                         if (zend_hash_get_current_key_ex(arr_hash, &key, &key_len, &index, 0, &pointer) == HASH_KEY_IS_STRING) {
1531                                                 PHPWRITE(key, key_len);
1532                                         } else {
1533                                                 DPRINTF("%s: credentials index %d\n", PHPFUNC, (int)index);
1534                                                 creds[j].type=index;
1535                                                 creds[j].result=emalloc( Z_STRLEN_PP(data) + 1 );
1536                                                 memset(creds[j].result, 0, Z_STRLEN_PP(data) + 1);
1537                                                 creds[j].resultlen=Z_STRLEN_PP(data);
1538                                                 strncpy(creds[j].result,Z_STRVAL_PP(data),Z_STRLEN_PP(data));
1539                                                 j++;
1540                                         }
1541                                 }
1542                 }
1543                 DPRINTF("%s: Found %d elements for credentials\n", PHPFUNC, j);
1544                 creds[0].count=j;
1545                 libvirt_virConnectAuth.cbdata = (void*)creds;
1546                 conn->conn = virConnectOpenAuth (url, &libvirt_virConnectAuth, readonly ? VIR_CONNECT_RO : 0);
1547                 for (i=0;i<creds[0].count;i++)
1548                         efree(creds[i].result);
1549                 efree(creds);
1550         }
1551
1552         if (conn->conn == NULL)
1553         {
1554                 DPRINTF("%s: Cannot establish connection to %s\n", PHPFUNC, url);
1555                 efree (conn);
1556                 RETURN_FALSE;
1557         }
1558
1559         resource_change_counter(INT_RESOURCE_CONNECTION, NULL, conn->conn, 1 TSRMLS_CC);
1560         DPRINTF("%s: Connection to %s established, returning %p\n", PHPFUNC, url, conn->conn);
1561
1562         ZEND_REGISTER_RESOURCE(return_value, conn, le_libvirt_connection);
1563         conn->resource_id=Z_LVAL_P(return_value);
1564 }
1565
1566 /*
1567         Function name:  libvirt_node_get_info
1568         Since version:  0.4.1(-1)
1569         Description:    Function is used to get the information about host node, mainly total memory installed, total CPUs installed and model information are useful
1570         Arguments:      @conn [resource]: resource for connection
1571         Returns:        array of node information or FALSE for error
1572 */
1573 PHP_FUNCTION(libvirt_node_get_info)
1574 {
1575         virNodeInfo info;
1576         php_libvirt_connection *conn=NULL;
1577         zval *zconn;
1578         int retval;
1579
1580         GET_CONNECTION_FROM_ARGS("r",&zconn);
1581
1582         retval=virNodeGetInfo   (conn->conn,&info);
1583         DPRINTF("%s: virNodeGetInfo returned %d\n", PHPFUNC, retval);
1584         if (retval==-1) RETURN_FALSE;
1585
1586         array_init(return_value);
1587         add_assoc_string_ex(return_value, "model", 6, info.model, 1);
1588         add_assoc_long(return_value, "memory", (long)info.memory);
1589         add_assoc_long(return_value, "cpus", (long)info.cpus);
1590         add_assoc_long(return_value, "nodes", (long)info.nodes);
1591         add_assoc_long(return_value, "sockets", (long)info.sockets);
1592         add_assoc_long(return_value, "cores", (long)info.cores);
1593         add_assoc_long(return_value, "threads", (long)info.threads);
1594         add_assoc_long(return_value, "mhz", (long)info.mhz);
1595 }
1596
1597 /*
1598         Function name:  libvirt_node_get_cpu_stats
1599         Since version:  0.4.6
1600         Description:    Function is used to get the CPU stats per nodes
1601         Arguments:      @conn [resource]: resource for connection
1602                         @cpunr [int]: CPU number to get information about, defaults to VIR_NODE_CPU_STATS_ALL_CPUS to get information about all CPUs
1603         Returns:        array of node CPU statistics including time (in seconds since UNIX epoch), cpu number and total number of CPUs on node or FALSE for error
1604 */
1605 #if LIBVIR_VERSION_NUMBER>=9003
1606 PHP_FUNCTION(libvirt_node_get_cpu_stats)
1607 {
1608         php_libvirt_connection *conn=NULL;
1609         zval *zconn;
1610         int cpuNum = VIR_NODE_CPU_STATS_ALL_CPUS;
1611         virNodeCPUStatsPtr params;
1612         virNodeInfo info;
1613         long cpunr = -1;
1614         int nparams = 0;
1615         int i, j, numCpus;
1616
1617         GET_CONNECTION_FROM_ARGS("r|l", &zconn, &cpunr);
1618
1619         if (virNodeGetInfo(conn->conn, &info) != 0) {
1620                 set_error("Cannot get number of CPUs" TSRMLS_CC);
1621                 RETURN_FALSE;
1622         }
1623
1624         numCpus = info.cpus;
1625         if (cpunr > numCpus - 1) {
1626                 char tmp[256] = { 0 };
1627                 snprintf(tmp, sizeof(tmp), "Invalid CPU number, valid numbers in range 0 to %d or VIR_NODE_CPU_STATS_ALL_CPUS",
1628                                 numCpus - 1);
1629                 set_error(tmp TSRMLS_CC);
1630
1631                 RETURN_FALSE;
1632         }
1633
1634         cpuNum = (int)cpunr;
1635
1636         if (virNodeGetCPUStats(conn->conn, cpuNum, NULL, &nparams, 0) != 0) {
1637                 set_error("Cannot get number of CPU stats" TSRMLS_CC);
1638                 RETURN_FALSE;
1639         }
1640
1641         if (nparams == 0) {
1642                 RETURN_TRUE;
1643         }
1644
1645         DPRINTF("%s: Number of parameters got from virNodeGetCPUStats is %d\n", __FUNCTION__, nparams);
1646
1647         params = calloc(nparams, nparams * sizeof(*params));
1648
1649         array_init(return_value);
1650         for (i = 0; i < 2; i++) {
1651                 zval *arr;
1652                 if (i > 0)
1653                         sleep(1);
1654
1655                 if (virNodeGetCPUStats(conn->conn, cpuNum, params, &nparams, 0) != 0) {
1656                         set_error("Unable to get node cpu stats" TSRMLS_CC);
1657                         RETURN_FALSE;
1658                 }
1659
1660                 ALLOC_INIT_ZVAL(arr);
1661                 array_init(arr);
1662
1663                 for (j = 0; j < nparams; j++) {
1664                         DPRINTF("%s: Field %s has value of %llu\n", __FUNCTION__, params[j].field, params[j].value);
1665
1666                         add_assoc_long(arr, params[j].field, params[j].value);
1667                 }
1668
1669                 add_assoc_long(arr, "time", time(NULL));
1670
1671                 add_index_zval(return_value, i, arr);
1672         }
1673
1674         add_assoc_long(return_value, "cpus", numCpus);
1675         if (cpuNum >= 0)
1676                 add_assoc_long(return_value, "cpu", cpunr);
1677         else
1678         if (cpuNum == VIR_NODE_CPU_STATS_ALL_CPUS)
1679                 add_assoc_string_ex(return_value, "cpu", 4, "all", 1);
1680         else
1681                 add_assoc_string_ex(return_value, "cpu", 4, "unknown", 1);
1682
1683         free(params);
1684         params = NULL;
1685 }
1686 #else
1687 PHP_FUNCTION(libvirt_node_get_cpu_stats)
1688 {
1689         set_error("Function is not supported by libvirt, support has been added in libvirt 0.9.3" TSRMLS_CC);
1690         RETURN_FALSE;
1691 }
1692 #endif
1693
1694 /*
1695         Function name:  libvirt_node_get_cpu_stats_for_each_cpu
1696         Since version:  0.4.6
1697         Description:    Function is used to get the CPU stats for each CPU on the host node
1698         Arguments:      @conn [resource]: resource for connection
1699                         @time [int]: time in seconds to get the information about, without aggregation for further processing
1700         Returns:        array of node CPU statistics for each CPU including time (in seconds since UNIX epoch), cpu number and total number of CPUs on node or FALSE for error
1701 */
1702 #if LIBVIR_VERSION_NUMBER>=9003
1703 PHP_FUNCTION(libvirt_node_get_cpu_stats_for_each_cpu)
1704 {
1705         php_libvirt_connection *conn=NULL;
1706         zval *zconn;
1707         virNodeCPUStatsPtr params;
1708         virNodeInfo info;
1709         int nparams = 0;
1710         long avg = 0, iter = 0;
1711         int done = 0;
1712         int i, j, numCpus;
1713         time_t startTime = 0;
1714         zval *time_array;
1715
1716         GET_CONNECTION_FROM_ARGS("r|l", &zconn, &avg);
1717
1718         if (virNodeGetInfo(conn->conn, &info) != 0) {
1719                 set_error("Cannot get number of CPUs" TSRMLS_CC);
1720                 RETURN_FALSE;
1721         }
1722
1723         if (virNodeGetCPUStats(conn->conn, VIR_NODE_CPU_STATS_ALL_CPUS, NULL, &nparams, 0) != 0) {
1724                 set_error("Cannot get number of CPU stats" TSRMLS_CC);
1725                 RETURN_FALSE;
1726         }
1727
1728         if (nparams == 0) {
1729                 RETURN_TRUE;
1730         }
1731
1732         DPRINTF("%s: Number of parameters got from virNodeGetCPUStats is %d\n", __FUNCTION__, nparams);
1733
1734         params = calloc(nparams, nparams * sizeof(*params));
1735
1736         numCpus = info.cpus;
1737         array_init(return_value);
1738
1739         startTime = time(NULL);
1740
1741         iter = 0;
1742         done = 0;
1743         while ( !done ) {
1744                 zval *arr;
1745
1746                 ALLOC_INIT_ZVAL(arr);
1747                 array_init(arr);
1748                 for (i = 0; i < numCpus; i++) {
1749                         zval *arr2;
1750
1751                         if (virNodeGetCPUStats(conn->conn, i, params, &nparams, 0) != 0) {
1752                                 set_error("Unable to get node cpu stats" TSRMLS_CC);
1753                                 RETURN_FALSE;
1754                         }
1755
1756                         ALLOC_INIT_ZVAL(arr2);
1757                         array_init(arr2);
1758
1759                         for (j = 0; j < nparams; j++)
1760                                 add_assoc_long(arr2, params[j].field, params[j].value);
1761
1762                         add_assoc_long(arr, "time", time(NULL));
1763                         add_index_zval(arr, i, arr2);
1764                 }
1765
1766                 add_index_zval(return_value, iter, arr);
1767
1768                 if ((avg <= 0) || (iter == avg - 1)) {
1769                         done = 1;
1770                         break;
1771                 }
1772
1773                 sleep(1);
1774                 iter++;
1775         }
1776
1777         ALLOC_INIT_ZVAL(time_array);
1778         array_init(time_array);
1779
1780         add_assoc_long(time_array, "start", startTime);
1781         add_assoc_long(time_array, "finish", time(NULL));
1782         add_assoc_long(time_array, "duration", time(NULL) - startTime);
1783
1784         add_assoc_zval(return_value, "times", time_array);
1785
1786         free(params);
1787         params = NULL;
1788 }
1789 #else
1790 PHP_FUNCTION(libvirt_node_get_cpu_stats_for_each_cpu)
1791 {
1792         set_error("Function is not supported by libvirt, support has been added in libvirt 0.9.3" TSRMLS_CC);
1793         RETURN_FALSE;
1794 }
1795 #endif
1796
1797 /*
1798         Function name:  libvirt_node_get_mem_stats
1799         Since version:  0.4.6
1800         Description:    Function is used to get the memory stats per node
1801         Arguments:      @conn [resource]: resource for connection
1802         Returns:        array of node memory statistics including time (in seconds since UNIX epoch) or FALSE for error
1803 */
1804 #if LIBVIR_VERSION_NUMBER>=9003
1805 PHP_FUNCTION(libvirt_node_get_mem_stats)
1806 {
1807         php_libvirt_connection *conn=NULL;
1808         zval *zconn;
1809         int memNum = VIR_NODE_MEMORY_STATS_ALL_CELLS;
1810         virNodeMemoryStatsPtr params;
1811         int nparams = 0;
1812         int j;
1813
1814         GET_CONNECTION_FROM_ARGS("r", &zconn);
1815
1816         if (virNodeGetMemoryStats(conn->conn, memNum, NULL, &nparams, 0) != 0) {
1817                 set_error("Cannot get number of memory stats" TSRMLS_CC);
1818                 RETURN_FALSE;
1819         }
1820
1821         if (nparams == 0) {
1822                 RETURN_TRUE;
1823         }
1824
1825         DPRINTF("%s: Number of parameters got from virNodeGetMemoryStats is %d\n", __FUNCTION__, nparams);
1826
1827         params = calloc(nparams, nparams * sizeof(*params));
1828
1829         array_init(return_value);
1830         if (virNodeGetMemoryStats(conn->conn, memNum, params, &nparams, 0) != 0) {
1831                 set_error("Unable to get node memory stats" TSRMLS_CC);
1832                 RETURN_FALSE;
1833         }
1834
1835         for (j = 0; j < nparams; j++) {
1836                 DPRINTF("%s: Field %s has value of %llu\n", __FUNCTION__, params[j].field, params[j].value);
1837
1838                 add_assoc_long(return_value, params[j].field, params[j].value);
1839         }
1840
1841         add_assoc_long(return_value, "time", time(NULL));
1842
1843         free(params);
1844         params = NULL;
1845 }
1846 #else
1847 PHP_FUNCTION(libvirt_node_get_mem_stats)
1848 {
1849         set_error("Function is not supported by libvirt, support has been added in libvirt 0.9.3" TSRMLS_CC);
1850         RETURN_FALSE;
1851 }
1852 #endif
1853
1854 //virsh capabilities | xpath '//capabilities/guest/arch[@name="x86_64"]/machine[@maxCpus=1]'
1855
1856 /*
1857         Function name:  libvirt_connect_get_machine_types
1858         Since version:  0.4.9
1859         Description:    Function is used to get machine types supported by hypervisor on the conneciton
1860         Arguments:      @conn [resource]: resource for connection
1861         Returns:        array of machine types for the connection incl. maxCpus if appropriate
1862 */
1863 PHP_FUNCTION(libvirt_connect_get_machine_types)
1864 {
1865         zval *zconn;
1866         php_libvirt_connection *conn = NULL;
1867         char *caps = NULL;
1868         char **ret = NULL;
1869         int i, num = -1;
1870
1871         GET_CONNECTION_FROM_ARGS("r",&zconn);
1872
1873         caps = virConnectGetCapabilities(conn->conn);
1874         if (caps == NULL)
1875                 RETURN_FALSE;
1876
1877         array_init(return_value);
1878
1879         ret = get_array_from_xpath(caps, "//capabilities/guest/arch/@name", &num);
1880         if (ret != NULL) {
1881                 for (i = 0; i < num; i++) {
1882                         int num2, j;
1883                         char tmp[1024] = { 0 };
1884
1885                         snprintf(tmp, sizeof(tmp), "//capabilities/guest/arch[@name=\"%s\"]/domain/@type", ret[i]);
1886                         char **ret2 = get_array_from_xpath(caps, tmp, &num2);
1887                         if (ret2 != NULL) {
1888                                 zval *arr2;
1889                                 ALLOC_INIT_ZVAL(arr2);
1890                                 array_init(arr2);
1891
1892                                 for (j = 0; j < num2; j++) {
1893                                         int num3, k;
1894                                         char tmp2[1024] = { 0 };
1895
1896                                         /* Common */
1897                                         zval *arr3;
1898                                         ALLOC_INIT_ZVAL(arr3);
1899                                         array_init(arr3);
1900
1901                                         snprintf(tmp2, sizeof(tmp2), "//capabilities/guest/arch[@name=\"%s\"]/machine",
1902                                                         ret[i]);
1903
1904                                         char **ret3 = get_array_from_xpath(caps, tmp2, &num3);
1905                                         if (ret3 != NULL) {
1906                                                 for (k = 0; k < num3; k++) {
1907                                                         char *numTmp = NULL;
1908                                                         char key[8] = { 0 };
1909                                                         char tmp3[2048] = { 0 };
1910
1911                                                         snprintf(key, sizeof(key), "%d", k);
1912                                                         //add_assoc_string_ex(arr2, key, strlen(key) + 1, ret3[k], 1);
1913
1914                                                         snprintf(tmp3, sizeof(tmp3), "//capabilities/guest/arch[@name=\"%s\"]/machine[text()=\"%s\"]/@maxCpus",
1915                                                                         ret[i], ret3[k]);
1916
1917                                                         numTmp = get_string_from_xpath(caps, tmp3, NULL, NULL);
1918                                                         if (numTmp == NULL)
1919                                                                 add_assoc_string_ex(arr2, key, strlen(key) + 1, ret3[k], 1);
1920                                                         else {
1921                                                                 zval *arr4;
1922                                                                 ALLOC_INIT_ZVAL(arr4);
1923                                                                 array_init(arr4);
1924
1925                                                                 add_assoc_string_ex(arr4, "name", 5, ret3[k], 1);
1926                                                                 add_assoc_string_ex(arr4, "maxCpus", 9, numTmp, 1);
1927
1928                                                                 add_assoc_zval_ex(arr2, key, strlen(key) + 1, arr4);
1929                                                                 free(numTmp);
1930                                                         }
1931
1932                                                         free(ret3[k]);
1933                                                 }
1934                                         }
1935
1936                                         /* Domain type specific */
1937                                         snprintf(tmp2, sizeof(tmp2), "//capabilities/guest/arch[@name=\"%s\"]/domain[@type=\"%s\"]/machine",
1938                                                         ret[i], ret2[j]);
1939
1940                                         ret3 = get_array_from_xpath(caps, tmp2, &num3);
1941                                         if (ret3 != NULL) {
1942                                                 for (k = 0; k < num3; k++) {
1943                                                         char key[8] = { 0 };
1944                                                         char tmp3[2048] = { 0 };
1945                                                         char *numTmp = NULL;
1946
1947                                                         snprintf(key, sizeof(key), "%d", k);
1948                                                         snprintf(tmp3, sizeof(tmp3),
1949                                                                 "//capabilities/guest/arch[@name=\"%s\"]/domain[@type=\"%s\"]/machine[text()=\"%s\"]/@maxCpus",
1950                                                                 ret[i], ret2[j], ret3[k]);
1951
1952                                                         numTmp = get_string_from_xpath(caps, tmp3, NULL, NULL);
1953                                                         if (numTmp == NULL)
1954                                                                 add_assoc_string_ex(arr3, key, strlen(key) + 1, ret3[k], 1);
1955                                                         else {
1956                                                                 zval *arr4;
1957                                                                 ALLOC_INIT_ZVAL(arr4);
1958                                                                 array_init(arr4);
1959
1960                                                                 add_assoc_string_ex(arr4, "name", 5, ret3[k], 1);
1961                                                                 add_assoc_string_ex(arr4, "maxCpus", 9, numTmp, 1);
1962
1963                                                                 add_assoc_zval_ex(arr3, key, strlen(key) + 1, arr4);
1964                                                                 free(numTmp);
1965                                                         }
1966
1967                                                         free(ret3[k]);
1968                                                 }
1969
1970                                                 add_assoc_zval_ex(arr2, ret2[j], strlen(ret2[j]) + 1, arr3);
1971                                         }
1972                                 }
1973                                 //free(ret2[j]);
1974
1975                                 add_assoc_zval_ex(return_value, ret[i], strlen(ret[i]) + 1, arr2);
1976                         }
1977                         free(ret[i]);
1978                 }
1979         }
1980 }
1981
1982 /*
1983         Function name:  libvirt_connect_get_information
1984         Since version:  0.4.1(-2)
1985         Description:    Function is used to get the information about the connection
1986         Arguments:      @conn [resource]: resource for connection
1987         Returns:        array of information about the connection
1988 */
1989 PHP_FUNCTION(libvirt_connect_get_information)
1990 {
1991         zval *zconn;
1992         char *tmp;
1993         unsigned long hvVer = 0;
1994         const char *type = NULL;
1995         char hvStr[64] = { 0 };
1996         int iTmp = -1, maxvcpus = -1;
1997         php_libvirt_connection *conn = NULL;
1998
1999         GET_CONNECTION_FROM_ARGS("r",&zconn);
2000
2001         tmp = virConnectGetURI(conn->conn);
2002         DPRINTF("%s: Got connection URI of %s...\n", PHPFUNC, tmp);
2003         array_init(return_value);
2004         add_assoc_string_ex(return_value, "uri", 4, tmp ? tmp : "unknown", 1);
2005         tmp = virConnectGetHostname(conn->conn);
2006         add_assoc_string_ex(return_value, "hostname", 9, tmp ? tmp : "unknown", 1);
2007
2008         if ((virConnectGetVersion(conn->conn, &hvVer) == 0) && (type = virConnectGetType(conn->conn)))
2009         {
2010                 add_assoc_string_ex(return_value, "hypervisor", 11, (char *)type, 1);
2011                 add_assoc_long(return_value, "hypervisor_major",(long)((hvVer/1000000) % 1000));
2012                 add_assoc_long(return_value, "hypervisor_minor",(long)((hvVer/1000) % 1000));
2013                 add_assoc_long(return_value, "hypervisor_release",(long)(hvVer %1000));
2014                 snprintf(hvStr, sizeof(hvStr), "%s %d.%d.%d", type,
2015                                         (long)((hvVer/1000000) % 1000), (long)((hvVer/1000) % 1000), (long)(hvVer %1000));
2016                 add_assoc_string_ex(return_value, "hypervisor_string", 18, hvStr, 1);
2017         }
2018
2019         if (strcmp(type, "QEMU") == 0) {
2020                 /* For QEMU the value is not reliable so we return -1 instead */
2021                 maxvcpus = -1;
2022         }
2023         else
2024                 maxvcpus = virConnectGetMaxVcpus(conn->conn, type);
2025
2026         add_assoc_long(return_value, "hypervisor_maxvcpus", maxvcpus);
2027         iTmp = virConnectIsEncrypted(conn->conn);
2028         if (iTmp == 1)
2029                 add_assoc_string_ex(return_value, "encrypted", 10, "Yes", 1);
2030         else
2031         if (iTmp == 0)
2032                 add_assoc_string_ex(return_value, "encrypted", 10, "No", 1);
2033         else
2034                 add_assoc_string_ex(return_value, "encrypted", 10, "unknown", 1);
2035
2036         iTmp = virConnectIsSecure(conn->conn);
2037         if (iTmp == 1)
2038                 add_assoc_string_ex(return_value, "secure", 7, "Yes", 1);
2039         else
2040         if (iTmp == 0)
2041                 add_assoc_string_ex(return_value, "secure", 7, "No", 1);
2042         else
2043                 add_assoc_string_ex(return_value, "secure", 7, "unknown", 1);
2044
2045         add_assoc_long(return_value, "num_inactive_domains", virConnectNumOfDefinedDomains(conn->conn));
2046         add_assoc_long(return_value, "num_inactive_interfaces", virConnectNumOfDefinedInterfaces(conn->conn));
2047         add_assoc_long(return_value, "num_inactive_networks", virConnectNumOfDefinedNetworks(conn->conn));
2048         add_assoc_long(return_value, "num_inactive_storagepools", virConnectNumOfDefinedStoragePools(conn->conn));
2049
2050         add_assoc_long(return_value, "num_active_domains", virConnectNumOfDomains(conn->conn));
2051         add_assoc_long(return_value, "num_active_interfaces", virConnectNumOfInterfaces(conn->conn));
2052         add_assoc_long(return_value, "num_active_networks", virConnectNumOfNetworks(conn->conn));
2053         add_assoc_long(return_value, "num_active_storagepools", virConnectNumOfStoragePools(conn->conn));
2054
2055         add_assoc_long(return_value, "num_total_domains", virConnectNumOfDomains(conn->conn) + virConnectNumOfDefinedDomains(conn->conn));
2056         add_assoc_long(return_value, "num_total_interfaces", virConnectNumOfInterfaces(conn->conn) + virConnectNumOfDefinedInterfaces(conn->conn));
2057         add_assoc_long(return_value, "num_total_networks", virConnectNumOfNetworks(conn->conn) + virConnectNumOfDefinedNetworks(conn->conn));
2058         add_assoc_long(return_value, "num_total_storagepools", virConnectNumOfStoragePools(conn->conn) +  virConnectNumOfDefinedStoragePools(conn->conn));
2059
2060         add_assoc_long(return_value, "num_secrets", virConnectNumOfSecrets(conn->conn));
2061         add_assoc_long(return_value, "num_nwfilters", virConnectNumOfNWFilters(conn->conn));
2062 }
2063
2064 /*
2065         Function name:  libvirt_connect_get_uri
2066         Since version:  0.4.1(-1)
2067         Description:    Function is used to get the connection URI. This is useful to check the hypervisor type of host machine when using "null" uri to libvirt_connect()
2068         Arguments:      @conn [resource]: resource for connection
2069         Returns:        connection URI string or FALSE for error
2070 */
2071 PHP_FUNCTION(libvirt_connect_get_uri)
2072 {
2073         zval *zconn;
2074         char *uri;
2075         char *uri_out;
2076         php_libvirt_connection *conn = NULL;
2077
2078         GET_CONNECTION_FROM_ARGS("r",&zconn);
2079         uri = virConnectGetURI(conn->conn);
2080         DPRINTF("%s: virConnectGetURI returned %s\n", PHPFUNC, uri);
2081         if (uri == NULL) RETURN_FALSE;
2082
2083         RECREATE_STRING_WITH_E(uri_out, uri);
2084         RETURN_STRING(uri_out, 0);
2085 }
2086
2087 /*
2088         Function name:  libvirt_connect_get_hostname
2089         Since version:  0.4.1(-1)
2090         Description:    Function is used to get the hostname of the guest associated with the connection
2091         Arguments:      @conn [resource]: resource for connection
2092         Returns:        hostname of the host node or FALSE for error
2093 */
2094 PHP_FUNCTION(libvirt_connect_get_hostname)
2095 {
2096         php_libvirt_connection *conn=NULL;
2097         zval *zconn;
2098         char *hostname;
2099         char *hostname_out;
2100
2101         GET_CONNECTION_FROM_ARGS("r",&zconn);
2102
2103         hostname=virConnectGetHostname(conn->conn);
2104         DPRINTF("%s: virConnectGetHostname returned %s\n", PHPFUNC, hostname);
2105         if (hostname==NULL) RETURN_FALSE;
2106
2107         RECREATE_STRING_WITH_E(hostname_out,hostname);
2108
2109         RETURN_STRING(hostname_out,0);
2110 }
2111
2112 /*
2113         Function name:  libvirt_image_create
2114         Since version:  0.4.2
2115         Description:    Function is used to create the image of desired name, size and format. The image will be created in the image path (libvirt.image_path INI variable). Works only o
2116         Arguments:              @conn [resource]: libvirt connection resource
2117                                 @name [string]: name of the image file that will be created in the libvirt.image_path directory
2118                                 @size [int]: size of the image in MiBs
2119                                 @format [string]: format of the image, may be raw, qcow or qcow2
2120         Returns:        hostname of the host node or FALSE for error
2121 */
2122
2123 PHP_FUNCTION(libvirt_image_create)
2124 {
2125         php_libvirt_connection *conn=NULL;
2126         zval *zconn;
2127         char msg[1024];
2128         char cmd[4096] = { 0 };
2129         char *path = NULL;
2130         char fpath[4096] = { 0 };
2131         char *image = NULL;
2132         int image_len;
2133         char *format;
2134         int format_len;
2135         long size;
2136         char *size_str;
2137         int size_str_len;
2138
2139         if (LIBVIRT_G(image_path_ini))
2140                 path = strdup( LIBVIRT_G(image_path_ini) );
2141
2142         if ((path == NULL) || (path[0] != '/')) {
2143                 set_error("Invalid argument, path must be set and absolute (start by slash character [/])" TSRMLS_CC);
2144                 RETURN_FALSE;
2145         }
2146
2147         GET_CONNECTION_FROM_ARGS("rsss",&zconn,&image,&image_len,&size_str,&size_str_len,&format,&format_len);
2148
2149         if (size_str == NULL)
2150                 RETURN_FALSE;
2151
2152         size = size_def_to_mbytes(size_str);
2153
2154         if (!is_local_connection(conn->conn)) {
2155             // TODO: Try to implement remote connection somehow. Maybe using SSH tunneling
2156                 snprintf(msg, sizeof(msg), "%s works only on local systems!", PHPFUNC);
2157                 set_error(msg TSRMLS_CC);
2158                 RETURN_FALSE;
2159         }
2160
2161         snprintf(fpath, sizeof(fpath), "%s/%s", path, image);
2162
2163         char *qemu_img_cmd = get_feature_binary("create-image");
2164         if (qemu_img_cmd == NULL) {
2165                 set_error("Feature 'create-image' is not supported" TSRMLS_CC);
2166                 RETURN_FALSE;
2167         }
2168
2169         snprintf(cmd, sizeof(cmd), "%s create -f %s %s %dM > /dev/null", qemu_img_cmd, format, fpath, size);
2170         free(qemu_img_cmd);
2171         DPRINTF("%s: Running '%s'...\n", PHPFUNC, cmd);
2172         system(cmd);
2173
2174         if (access(fpath, F_OK) == 0) {
2175                 RETURN_TRUE;
2176         }
2177         else {
2178                 snprintf(msg, sizeof(msg), "Cannot create image: %s", fpath);
2179                 set_error(msg TSRMLS_CC);
2180                 RETURN_FALSE;
2181         }
2182 }
2183
2184 /*
2185         Function name:  libvirt_image_remove
2186         Since version:  0.4.2
2187         Description:    Function is used to create the image of desired name, size and format. The image will be created in the image path (libvirt.image_path INI variable). Works only on local systems!
2188         Arguments:      @conn [resource]: libvirt connection resource
2189                         @image [string]: name of the image file that should be deleted
2190         Returns:        hostname of the host node or FALSE for error
2191 */
2192 PHP_FUNCTION(libvirt_image_remove)
2193 {
2194         php_libvirt_connection *conn=NULL;
2195         zval *zconn;
2196         char *hostname;
2197         char name[1024];
2198         char msg[4096] = { 0 };
2199         char *image = NULL;
2200         int image_len;
2201
2202         GET_CONNECTION_FROM_ARGS("rs",&zconn,&image,&image_len);
2203
2204         hostname=virConnectGetHostname(conn->conn);
2205
2206         /* Get the current hostname to check if we're on local machine */
2207         gethostname(name, 1024);
2208         if (strcmp(name, hostname) != 0) {
2209                 snprintf(msg, sizeof(msg), "%s works only on local systems!", PHPFUNC);
2210                 set_error(msg TSRMLS_CC);
2211                 RETURN_FALSE;
2212         }
2213
2214         if (unlink(image) != 0) {
2215                 snprintf(msg, sizeof(msg), "An error occured while unlinking %s: %d (%s)", image, errno, strerror(errno));
2216                 set_error(msg TSRMLS_CC);
2217                 RETURN_FALSE;
2218         }
2219         else {
2220                 RETURN_TRUE;
2221         }
2222 }
2223
2224 /*
2225         Function name:  libvirt_connect_get_hypervisor
2226         Since version:  0.4.1(-2)
2227         Description:    Function is used to get the information about the hypervisor on the connection identified by the connection pointer
2228         Arguments:      @conn [resource]: resource for connection
2229         Returns:        array of hypervisor information if available
2230 */
2231 PHP_FUNCTION(libvirt_connect_get_hypervisor)
2232 {
2233         php_libvirt_connection *conn=NULL;
2234         zval *zconn;
2235         unsigned long hvVer = 0;
2236         const char *type = NULL;
2237         char hvStr[64] = { 0 };
2238
2239         GET_CONNECTION_FROM_ARGS("r",&zconn);
2240
2241         if (virConnectGetVersion(conn->conn, &hvVer) != 0)
2242                 RETURN_FALSE;
2243
2244         type = virConnectGetType(conn->conn);
2245         if (type == NULL)
2246                 RETURN_FALSE;
2247
2248         DPRINTF("%s: virConnectGetType returned %s\n", PHPFUNC, type);
2249
2250         array_init(return_value);
2251         add_assoc_string_ex(return_value, "hypervisor", 11, (char *)type, 1);
2252         add_assoc_long(return_value, "major",(long)((hvVer/1000000) % 1000));
2253         add_assoc_long(return_value, "minor",(long)((hvVer/1000) % 1000));
2254         add_assoc_long(return_value, "release",(long)(hvVer %1000));
2255
2256         snprintf(hvStr, sizeof(hvStr), "%s %d.%d.%d", type,
2257                                 (long)((hvVer/1000000) % 1000), (long)((hvVer/1000) % 1000), (long)(hvVer %1000));
2258         add_assoc_string_ex(return_value, "hypervisor_string", 18, hvStr, 1);
2259 }
2260
2261 /*
2262         Function name:  libvirt_connect_is_encrypted
2263         Since version:  0.4.1(-2)
2264         Description:    Function is used to get the information whether the connection is encrypted or not
2265         Arguments:      @conn [resource]: resource for connection
2266         Returns:        1 if encrypted, 0 if not encrypted, -1 on error
2267 */
2268 PHP_FUNCTION(libvirt_connect_get_encrypted)
2269 {
2270         php_libvirt_connection *conn=NULL;
2271         zval *zconn;
2272
2273         GET_CONNECTION_FROM_ARGS("r",&zconn);
2274
2275         RETURN_LONG( virConnectIsEncrypted(conn->conn) );
2276 }
2277
2278
2279 /*
2280         Function name:  libvirt_connect_is_secure
2281         Since version:  0.4.1(-2)
2282         Description:    Function is used to get the information whether the connection is secure or not
2283         Arguments:      @conn [resource]: resource for connection
2284         Returns:        1 if secure, 0 if not secure, -1 on error
2285 */
2286 PHP_FUNCTION(libvirt_connect_get_secure)
2287 {
2288         php_libvirt_connection *conn=NULL;
2289         zval *zconn;
2290
2291         GET_CONNECTION_FROM_ARGS("r",&zconn);
2292
2293         RETURN_LONG( virConnectIsSecure(conn->conn) );
2294 }
2295
2296 /*
2297         Function name:  libvirt_connect_get_maxvcpus
2298         Since version:  0.4.1(-2)
2299         Description:    Function is used to get maximum number of VCPUs per VM on the hypervisor connection
2300         Arguments:      @conn [resource]: resource for connection
2301         Returns:        number of VCPUs available per VM on the connection or FALSE for error
2302 */
2303 PHP_FUNCTION(libvirt_connect_get_maxvcpus)
2304 {
2305         php_libvirt_connection *conn=NULL;
2306         zval *zconn;
2307         const char *type = NULL;
2308
2309         GET_CONNECTION_FROM_ARGS("r",&zconn);
2310
2311         type = virConnectGetType(conn->conn);
2312         if (type == NULL)
2313                 RETURN_FALSE;
2314
2315         RETURN_LONG(virConnectGetMaxVcpus(conn->conn, type));
2316 }
2317
2318 /*
2319         Function name:  libvirt_connect_get_sysinfo
2320         Since version:  0.4.1(-2)
2321         Description:    Function is used to get the system information from connection if available
2322         Arguments:      @conn [resource]: resource for connection
2323         Returns:        XML description of system information from the connection or FALSE for error
2324 */
2325 #if LIBVIR_VERSION_NUMBER>=8008
2326 PHP_FUNCTION(libvirt_connect_get_sysinfo)
2327 {
2328         php_libvirt_connection *conn=NULL;
2329         zval *zconn;
2330         char *sysinfo;
2331         char *sysinfo_out;
2332
2333         GET_CONNECTION_FROM_ARGS("r",&zconn);
2334
2335         sysinfo=virConnectGetSysinfo(conn->conn, 0);
2336         if (sysinfo==NULL) RETURN_FALSE;
2337
2338         RECREATE_STRING_WITH_E(sysinfo_out, sysinfo);
2339
2340         RETURN_STRING(sysinfo_out,0);
2341 }
2342 #else
2343 PHP_FUNCTION(libvirt_connect_get_sysinfo)
2344 {
2345         set_error("Only libvirt 0.8.8 or higher supports virConnectGetSysinfo() API function" TSRMLS_CC);
2346         RETURN_FALSE;
2347 }
2348 #endif
2349
2350 /*
2351         Private function name:  get_string_from_xpath
2352         Since version:          0.4.1(-1)
2353         Description:            Function is used to get the XML xPath expression from the XML document. This can be added to val array if not NULL.
2354         Arguments:              @xml [string]: input XML document
2355                                 @xpath [string]: xPath expression to find nodes in the XML document
2356                                 @val [array]: Zend array resource to put data to
2357                                 @retVal [int]: return value of the parsing
2358         Returns:                string containing data of last match found
2359 */
2360 char *get_string_from_xpath(char *xml, char *xpath, zval **val, int *retVal)
2361 {
2362         xmlParserCtxtPtr xp;
2363         xmlDocPtr doc;
2364         xmlXPathContextPtr context;
2365         xmlXPathObjectPtr result;
2366         xmlNodeSetPtr nodeset;
2367         int ret = 0, i;
2368         char *value = NULL;
2369         char key[8] = { 0 };
2370
2371         if ((xpath == NULL) || (xml == NULL))
2372         {
2373                 return NULL;
2374         }
2375
2376         xp = xmlCreateDocParserCtxt( (xmlChar *)xml );
2377         if (!xp) {
2378                 if (retVal)
2379                         *retVal = -1;
2380                 return NULL;
2381         }
2382         doc = xmlCtxtReadDoc(xp, (xmlChar *)xml, NULL, NULL, 0);
2383         if (!doc) {
2384                 if (retVal)
2385                         *retVal = -2;
2386                 xmlCleanupParser();
2387                 return NULL;
2388         }
2389
2390         context = xmlXPathNewContext(doc);
2391         if (!context) {
2392                 if (retVal)
2393                         *retVal = -3;
2394                 xmlCleanupParser();
2395                 return NULL;
2396         }
2397
2398         result = xmlXPathEvalExpression( (xmlChar *)xpath, context);
2399         if (!result) {
2400                 if (retVal)
2401                         *retVal = -4;
2402                 xmlXPathFreeContext(context);
2403                 xmlCleanupParser();
2404                 return NULL;
2405         }
2406
2407         if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
2408                 xmlXPathFreeObject(result);
2409                 xmlXPathFreeContext(context);
2410                 xmlCleanupParser();
2411                 if (retVal)
2412                         *retVal = 0;
2413                 return NULL;
2414         }
2415
2416         nodeset = result->nodesetval;
2417         ret = nodeset->nodeNr;
2418
2419         if (ret == 0) {
2420                 xmlXPathFreeObject(result);
2421                 xmlFreeDoc(doc);
2422                 xmlXPathFreeContext(context);
2423                 xmlCleanupParser();
2424                 if (retVal)
2425                         *retVal = 0;
2426                 return NULL;
2427         }
2428
2429         if (val != NULL) {
2430                 ret = 0;
2431                 for (i = 0; i < nodeset->nodeNr; i++) {
2432                         if (xmlNodeListGetString(doc, nodeset->nodeTab[i]->xmlChildrenNode, 1) != NULL) {
2433                                 value = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[i]->xmlChildrenNode, 1);
2434
2435                                 snprintf(key, sizeof(key), "%d", i);
2436                                 add_assoc_string_ex(*val, key, strlen(key)+1, value, 1);
2437                                 ret++;
2438                         }
2439                 }
2440                 add_assoc_long(*val, "num", (long)ret);
2441         }
2442         else {
2443                 if (xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1) != NULL)
2444                         value = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
2445         }
2446
2447         xmlXPathFreeContext(context);
2448         xmlXPathFreeObject(result);
2449         xmlFreeDoc(doc);
2450         xmlCleanupParser();
2451
2452         if (retVal)
2453                 *retVal = ret;
2454
2455         return (value != NULL) ? strdup(value) : NULL;
2456 }
2457
2458 /*
2459         Private function name:  get_array_from_xpath
2460         Since version:          0.4.9
2461         Description:            Function is used to get all XPath elements from XML and return in array (character pointer)
2462         Arguments:              @xml [string]: input XML document
2463                                 @xpath [string]: xPath expression to find nodes in the XML document
2464                                 @num [int *]: number of elements
2465         Returns:                pointer to char ** if successful or NULL for error
2466 */
2467 char **get_array_from_xpath(char *xml, char *xpath, int *num)
2468 {
2469         xmlParserCtxtPtr xp;
2470         xmlDocPtr doc;
2471         xmlXPathContextPtr context;
2472         xmlXPathObjectPtr result;
2473         xmlNodeSetPtr nodeset;
2474         int ret = 0, i;
2475         char *value = NULL;
2476         char **val = NULL;
2477
2478         if ((xpath == NULL) || (xml == NULL))
2479                 return NULL;
2480
2481         xp = xmlCreateDocParserCtxt( (xmlChar *)xml );
2482         if (!xp)
2483                 return NULL;
2484
2485         doc = xmlCtxtReadDoc(xp, (xmlChar *)xml, NULL, NULL, 0);
2486         if (!doc) {
2487                 xmlCleanupParser();
2488                 return NULL;
2489         }
2490
2491         context = xmlXPathNewContext(doc);
2492         if (!context) {
2493                 xmlCleanupParser();
2494                 return NULL;
2495         }
2496
2497         result = xmlXPathEvalExpression( (xmlChar *)xpath, context);
2498         if (!result) {
2499                 xmlXPathFreeContext(context);
2500                 xmlCleanupParser();
2501                 return NULL;
2502         }
2503
2504         if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
2505                 xmlXPathFreeObject(result);
2506                 xmlXPathFreeContext(context);
2507                 xmlCleanupParser();
2508                 return NULL;
2509         }
2510
2511         nodeset = result->nodesetval;
2512         ret = nodeset->nodeNr;
2513
2514         if (ret == 0) {
2515                 xmlXPathFreeObject(result);
2516                 xmlFreeDoc(doc);
2517                 xmlXPathFreeContext(context);
2518                 xmlCleanupParser();
2519                 if (num != NULL)
2520                         *num = 0;
2521                 return NULL;
2522         }
2523
2524         ret = 0;
2525         val = (char **)malloc( nodeset->nodeNr  * sizeof(char *) );
2526         for (i = 0; i < nodeset->nodeNr; i++) {
2527                 if (xmlNodeListGetString(doc, nodeset->nodeTab[i]->xmlChildrenNode, 1) != NULL) {
2528                         value = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[i]->xmlChildrenNode, 1);
2529
2530                         val[ret++] = strdup(value);
2531                 }
2532         }
2533
2534         xmlXPathFreeContext(context);
2535         xmlXPathFreeObject(result);
2536         xmlFreeDoc(doc);
2537         xmlCleanupParser();
2538
2539         if (num != NULL)
2540                 *num = ret;
2541
2542         return val;
2543 }
2544
2545 /*
2546         Private function name:  dec_to_bin
2547         Since version:          0.4.1(-1)
2548         Description:            Function dec_to_bin() converts the unsigned long long decimal (used e.g. for IPv4 address) to it's binary representation
2549         Arguments:              @decimal [int]: decimal value to be converted to binary interpretation
2550                                 @binary [string]: output binary string with the binary interpretation
2551         Returns:                None
2552 */
2553 void dec_to_bin(long long decimal, char *binary)
2554 {
2555         int  k = 0, n = 0;
2556         int  neg_flag = 0;
2557         int  remain;
2558         // int  old_decimal;
2559         char temp[128] = { 0 };
2560
2561         if (decimal < 0)
2562         {
2563                 decimal = -decimal;
2564                 neg_flag = 1;
2565         }
2566         do
2567         {
2568                 // old_decimal = decimal;
2569                 remain    = decimal % 2;
2570                 decimal   = decimal / 2;
2571                 temp[k++] = remain + '0';
2572         } while (decimal > 0);
2573
2574         if (neg_flag)
2575                 temp[k++] = '-';
2576         else
2577                 temp[k++] = ' ';
2578
2579         while (k >= 0)
2580                 binary[n++] = temp[--k];
2581
2582         binary[n-1] = 0;
2583 }
2584
2585 /*
2586         Private function name:  get_subnet_bits
2587         Since version:          0.4.1(-1)
2588         Description:            Function is used to get number of bits used by subnet determined by IP. Useful to get the CIDR IPv4 address representation
2589         Arguments:              @ip [string]: IP address to calculate subnet bits from
2590         Returns:                number of bits used by subnet mask
2591 */
2592 int get_subnet_bits(char *ip)
2593 {
2594         char tmp[4] = { 0 };
2595         int i, part = 0, ii = 0, skip = 0;
2596         unsigned long long retval = 0;
2597         char *binary;
2598         int maxBits = 64;
2599
2600         for (i = 0; i < strlen(ip); i++) {
2601                 if (ip[i] == '.') {
2602                         ii = 0;
2603                         retval += (atoi(tmp) * pow(256, 3 - part));
2604                         part++;
2605                         memset(tmp, 0, 4);
2606                 }
2607                 else {
2608                         tmp[ii++] = ip[i];
2609                 }
2610         }
2611
2612         retval += (atoi(tmp) * pow(256, 3 - part));
2613         binary = (char *)malloc( maxBits * sizeof(char) );
2614         dec_to_bin(retval, binary);
2615
2616         for (i = 0; i < strlen(binary); i++) {
2617                 if ((binary[i] != '1') && (binary[i] != '0'))
2618                         skip++;
2619                 else
2620                 if (binary[i] != '1')
2621                         break;
2622         }
2623         free(binary);
2624
2625         return i - skip;
2626 }
2627
2628 /*
2629         Private function name:  get_next_free_numeric_value
2630         Since version:          0.4.2
2631         Description:            Function is used to get the next free slot to be used for adding new NIC device or others
2632         Arguments:              @res [virDomainPtr]: standard libvirt domain pointer identified by virDomainPtr
2633                                 @xpath [string]: xPath expression of items to get the next free value of
2634         Returns:                next free numeric value
2635 */
2636 long get_next_free_numeric_value(virDomainPtr domain, char *xpath)
2637 {
2638         zval *output = NULL;
2639         char *xml;
2640         int retval = -1;
2641         HashTable *arr_hash;
2642         HashPosition pointer;
2643         // int array_count;
2644         zval **data;
2645         char *key;
2646         unsigned int key_len;
2647         unsigned long index;
2648         long max_slot = -1;
2649
2650         xml=virDomainGetXMLDesc(domain, VIR_DOMAIN_XML_INACTIVE);
2651         output = emalloc( sizeof(zval) );
2652         array_init(output);
2653         free( get_string_from_xpath(xml, xpath, &output, &retval) );
2654
2655         arr_hash = Z_ARRVAL_P(output);
2656         // array_count = zend_hash_num_elements(arr_hash);
2657         for (zend_hash_internal_pointer_reset_ex(arr_hash, &pointer);
2658                         zend_hash_get_current_data_ex(arr_hash, (void**) &data, &pointer) == SUCCESS;
2659                         zend_hash_move_forward_ex(arr_hash, &pointer)) {
2660                         if (Z_TYPE_PP(data) == IS_STRING) {
2661                                 if (zend_hash_get_current_key_ex(arr_hash, &key, &key_len, &index, 0, &pointer) != HASH_KEY_IS_STRING) {
2662                                         unsigned int num = -1;
2663
2664                                         sscanf(Z_STRVAL_PP(data), "%x", &num);
2665                                         if (num > max_slot)
2666                                                 max_slot = num;
2667                                 }
2668                 }
2669         }
2670
2671         efree(output);
2672         return max_slot + 1;
2673 }
2674
2675 /*
2676         Private function name:  connection_get_domain_type
2677         Since version:          0.4.5
2678         Description:            Function is required for functions that get the emulator for specific libvirt connection
2679         Arguments:              @conn [virConnectPtr]: libvirt connection pointer of connection to get emulator for
2680                                 @arch [string]: optional architecture string, can be NULL to get default
2681         Returns:                path to the emulator
2682 */
2683 char *connection_get_domain_type(virConnectPtr conn, char *arch TSRMLS_DC)
2684 {
2685         int retval = -1;
2686         char *tmp = NULL;
2687         char *caps = NULL;
2688         char xpath[1024] = { 0 };
2689
2690         caps = virConnectGetCapabilities(conn);
2691         if (caps == NULL)
2692                 return NULL;
2693
2694         if (arch == NULL) {
2695                 arch = get_string_from_xpath(caps, "//capabilities/host/cpu/arch", NULL, &retval);
2696                 DPRINTF("%s: No architecture defined, got '%s' from capabilities XML\n", __FUNCTION__, arch);
2697                 if ((arch == NULL) || (retval < 0))
2698                         return NULL;
2699         }
2700
2701         DPRINTF("%s: Requested domain type for arch '%s'\n",  __FUNCTION__, arch);
2702
2703         snprintf(xpath, sizeof(xpath), "//capabilities/guest/arch[@name='%s']/domain/@type", arch);
2704         DPRINTF("%s: Applying xPath '%s' to capabilities XML output\n", __FUNCTION__, xpath);
2705         tmp = get_string_from_xpath(caps, xpath, NULL, &retval);
2706         if ((tmp == NULL) || (retval < 0)) {
2707                 DPRINTF("%s: No domain type found in XML...\n", __FUNCTION__);
2708                 return NULL;
2709         }
2710
2711         DPRINTF("%s: Domain type is '%s'\n",  __FUNCTION__, tmp);
2712
2713         return tmp;
2714 }
2715
2716 /*
2717         Private function name:  connection_get_emulator
2718         Since version:          0.4.5
2719         Description:            Function is required for functions that get the emulator for specific libvirt connection
2720         Arguments:              @conn [virConnectPtr]: libvirt connection pointer of connection to get emulator for
2721                                 @arch [string]: optional architecture string, can be NULL to get default
2722         Returns:                path to the emulator
2723 */
2724 char *connection_get_emulator(virConnectPtr conn, char *arch TSRMLS_DC)
2725 {
2726         int retval = -1;
2727         char *tmp = NULL;
2728         char *caps = NULL;
2729         char xpath[1024] = { 0 };
2730
2731         caps = virConnectGetCapabilities(conn);
2732         if (caps == NULL)
2733                 return NULL;
2734
2735         if (arch == NULL) {
2736                 arch = get_string_from_xpath(caps, "//capabilities/host/cpu/arch", NULL, &retval);
2737                 DPRINTF("%s: No architecture defined, got '%s' from capabilities XML\n", __FUNCTION__, arch);
2738                 if ((arch == NULL) || (retval < 0))
2739                         return NULL;
2740         }
2741
2742         DPRINTF("%s: Requested emulator for arch '%s'\n",  __FUNCTION__, arch);
2743
2744         snprintf(xpath, sizeof(xpath), "//capabilities/guest/arch[@name='%s']/domain/emulator", arch);
2745         DPRINTF("%s: Applying xPath '%s' to capabilities XML output\n", __FUNCTION__, xpath);
2746         tmp = get_string_from_xpath(caps, xpath, NULL, &retval);
2747         if ((tmp == NULL) || (retval < 0)) {
2748                 DPRINTF("%s: No emulator found. Trying next location ...\n", __FUNCTION__);
2749                 snprintf(xpath, sizeof(xpath), "//capabilities/guest/arch[@name='%s']/emulator", arch);
2750         }
2751         else {
2752                 DPRINTF("%s: Emulator is '%s'\n",  __FUNCTION__, tmp);
2753                 return tmp;
2754         }
2755
2756         DPRINTF("%s: Applying xPath '%s' to capabilities XML output\n",  __FUNCTION__, xpath);
2757
2758         tmp = get_string_from_xpath(caps, xpath, NULL, &retval);
2759         if ((tmp == NULL) || (retval < 0)) {
2760                 DPRINTF("%s: Emulator is '%s'\n",  __FUNCTION__, tmp);
2761                 return NULL;
2762         }
2763
2764         DPRINTF("%s: Emulator is '%s'\n",  __FUNCTION__, tmp);
2765
2766         return tmp;
2767 }
2768
2769 /*
2770         Private function name:  connection_get_arch
2771         Since version:          0.4.5
2772         Description:            Function is required for functions that get the architecture for specific libvirt connection
2773         Arguments:              @conn [virConnectPtr]: libvirt connection pointer of connection to get architecture for
2774         Returns:                path to the emulator
2775 */
2776 char *connection_get_arch(virConnectPtr conn TSRMLS_DC)
2777 {
2778         int retval = -1;
2779         char *tmp = NULL;
2780         char *caps = NULL;
2781         // char xpath[1024] = { 0 };
2782
2783         caps = virConnectGetCapabilities(conn);
2784         if (caps == NULL)
2785                 return NULL;
2786
2787         tmp = get_string_from_xpath(caps, "//capabilities/host/cpu/arch", NULL, &retval);
2788         free(caps);
2789
2790         if ((tmp == NULL) || (retval < 0)) {
2791                 DPRINTF("%s: Cannot get host CPU architecture from capabilities XML\n", __FUNCTION__);
2792                 return NULL;
2793         }
2794
2795         DPRINTF("%s: Host CPU architecture is '%s'\n",  __FUNCTION__, tmp);
2796
2797         return tmp;
2798 }
2799
2800 /*
2801         Private function name:  generate_uuid_any
2802         Since version:          0.4.5
2803         Description:            Function is used to generate a new random UUID string
2804         Arguments:              None
2805         Returns:                a new random UUID string
2806 */
2807 char *generate_uuid_any()
2808 {
2809         int i;
2810         char a[37] = { 0 };
2811         char hexa[] = "0123456789abcdef";
2812         // virDomainPtr domain=NULL;
2813
2814         srand(time(NULL));
2815         for (i = 0; i < 36; i++) {
2816                 if ((i == 8) || (i == 13) || (i == 18) || (i == 23))
2817                         a[i] = '-';
2818                 else
2819                         a[i] = hexa[ rand() % strlen(hexa) ];
2820         }
2821
2822         return strdup( a );
2823 }
2824
2825 /*
2826         Private function name:  generate_uuid
2827         Since version:          0.4.5
2828         Description:            Function is used to generate a new unused UUID string
2829         Arguments:              @conn [virConnectPtr]: libvirt connection pointer
2830         Returns:                a new unused random UUID string
2831 */
2832 char *generate_uuid(virConnectPtr conn TSRMLS_DC)
2833 {
2834         virDomainPtr domain=NULL;
2835         char *uuid = NULL;
2836         int old_error_reporting = EG(error_reporting);
2837         EG(error_reporting) = 0;
2838
2839         uuid = generate_uuid_any();
2840         while ((domain = virDomainLookupByUUIDString(conn, uuid)) != NULL) {
2841                 virDomainFree(domain);
2842                 uuid = generate_uuid_any();
2843         }
2844         EG(error_reporting) = old_error_reporting;
2845
2846         DPRINTF("%s: Generated new UUID '%s'\n", __FUNCTION__, uuid);
2847         return uuid;
2848 }
2849
2850 /*
2851         Private function name:  get_disk_xml
2852         Since version:          0.4.5
2853         Description:            Function is used to format single disk XML
2854         Arguments:              @size [unsigned long long]: size of disk for generating a new one (can be -1 not to generate even if it doesn't exist)
2855                                 @path [string]: path to the storage on the host system
2856                                 @driver [string]: driver to be used to access the disk
2857                                 @dev [string]: device to be presented to the guest
2858                                 @disk_flags [int]: disk type, VIR_DOMAIN_DISK_FILE or VIR_DOMAIN_DISK_BLOCK
2859         Returns:                XML output for the disk
2860 */
2861 char *get_disk_xml(unsigned long long size, char *path, char *driver, char *bus, char *dev, int disk_flags TSRMLS_DC)
2862 {
2863         char xml[4096] = { 0 };
2864
2865         if ((path == NULL) || (driver == NULL) || (bus == NULL))
2866                 return NULL;
2867
2868         if (access(path, R_OK) != 0) {
2869                 if (disk_flags & DOMAIN_DISK_BLOCK) {
2870                         DPRINTF("%s: Cannot access block device %s\n", __FUNCTION__, path);
2871                         return NULL;
2872                 }
2873
2874                 int ret = 0;
2875                 char cmd[4096] = { 0 };
2876                 DPRINTF("%s: Cannot access disk image %s\n", __FUNCTION__, path);
2877
2878                 if (size == -1) {
2879                         DPRINTF("%s: Invalid size. Cannot create image\n", __FUNCTION__);
2880                         return NULL;
2881                 }
2882
2883                 char *qemu_img_cmd = get_feature_binary("create-image");
2884                 if (qemu_img_cmd == NULL) {
2885                         DPRINTF("%s: Binary for creating disk images doesn't exist\n", __FUNCTION__);
2886                         return NULL;
2887                 }
2888
2889                 // TODO: implement backing file handling: -o backing_file=RAW_IMG_FILE QCOW_IMG
2890                 snprintf(cmd, sizeof(cmd), "%s create -f %s %s %ldM > /dev/null &2>/dev/null", qemu_img_cmd, driver, path, size);
2891                 free(qemu_img_cmd);
2892
2893                 int cmdRet = system(cmd);
2894                 ret = WEXITSTATUS(cmdRet);
2895                 DPRINTF("%s: Command '%s' finished with error code %d\n", __FUNCTION__, cmd, ret);
2896                 if (ret != 0) {
2897                         DPRINTF("%s: File creation failed\n", path);
2898                         return NULL;
2899                 }
2900
2901                 if (disk_flags & DOMAIN_DISK_ACCESS_ALL) {
2902                         DPRINTF("%s: Disk flag for all user access found, setting up %s' permissions to 0666\n", __FUNCTION__, path);
2903                         chmod(path, 0666);
2904                 }
2905         }
2906
2907         snprintf(xml, sizeof(xml), "\t\t<disk type='%s' device='disk'>\n"
2908                                                                 "\t\t\t<driver name='qemu' type='%s' />\n"
2909                                                                 "\t\t\t<source file='%s'/>\n"
2910                                                                 "\t\t\t<target bus='%s' dev='%s' />\n"
2911                                                                 "\t\t</disk>\n",
2912                                                                 (disk_flags & DOMAIN_DISK_FILE) ? "file" :
2913                                                                 ((disk_flags & DOMAIN_DISK_BLOCK) ? "block" : ""),
2914                                                                 driver, path, bus, dev);
2915         return strdup( xml );
2916 }
2917 /*
2918         Private function name:  get_network_xml
2919         Since version:          0.4.5
2920         Description:            Function is used to format single network interface XML
2921         Arguments:              @mac [string]: MAC address of the new interface
2922                                 @network [string]: network name
2923                                 @model [string]: optional model name
2924         Returns:                XML output for the network interface
2925 */
2926 char *get_network_xml(char *mac, char *network, char *model)
2927 {
2928         char xml[4096] = { 0 };
2929
2930         if ((mac == NULL) || (network == NULL))
2931                 return NULL;
2932
2933         if (model == NULL)
2934                 snprintf(xml, sizeof(xml), "\t\t<interface type='network'>\n"
2935                                                                         "\t\t\t<mac address='%s'/>\n"
2936                                                                         "\t\t\t<source network='%s'/>\n"
2937                                                                         "\t\t</interface>\n",
2938                                                                         mac, network);
2939         else
2940                 snprintf(xml, sizeof(xml), "\t\t<interface type='network'>\n"
2941                                                                         "\t\t\t<mac address='%s'/>\n"
2942                                                                         "\t\t\t<source network='%s'/>\n"
2943                                                                         "\t\t\t<model type='%s'/>\n"
2944                                                                         "\t\t</interface>\n",
2945                                                                         mac, network, model);
2946
2947         return strdup( xml );
2948 }
2949
2950 /*
2951         Private function name:  installation_get_xml
2952         Since version:          0.4.5
2953         Description:            Function is used to generate the installation XML description to install a new domain
2954         Arguments:              @step [int]: number of step for XML output (1 or 2)
2955                                 @conn [virConnectPtr]: libvirt connection pointer
2956                                 @name [string]: name of the new virtual machine
2957                                 @memMB [int]: memory in Megabytes
2958                                 @maxmemMB [int]: maximum memory in Megabytes
2959                                 @arch [string]: architecture to be used for the new domain, may be NULL to use the hypervisor default
2960                                 @uuid [string]: UUID to be used or NULL to generate a new one
2961                                 @vCpus [int]: number of virtual CPUs for the domain
2962                                 @iso_image [string]: ISO image for the installation
2963                                 @disks [tVMDisk]: disk structure with all the disks defined
2964                                 @numDisks [int]: number of disks in the disk structure
2965                                 @networks [tVMNetwork]: network structure with all the networks defined
2966                                 @numNetworks [int]: number of networks in the network structure
2967                                 @domain_flags [int]: flags for the domain installation
2968         Returns:                full XML output for installation
2969 */
2970 char *installation_get_xml(int step, virConnectPtr conn, char *name, int memMB, int maxmemMB, char *arch, char *uuid, int vCpus, char *iso_image,
2971                                                         tVMDisk *disks, int numDisks, tVMNetwork *networks, int numNetworks, int domain_flags TSRMLS_DC)
2972 {
2973         int i;
2974         char xml[32768] = { 0 };
2975         char disks_xml[16384] = { 0 };
2976         char networks_xml[16384] = { 0 };
2977         char features[128] = { 0 };
2978         char *tmp = NULL;
2979         char type[64] = { 0 };
2980         // virDomainPtr domain=NULL;
2981
2982         if (conn == NULL) {
2983                 DPRINTF("%s: Invalid libvirt connection pointer\n", __FUNCTION__);
2984                 return NULL;
2985         }
2986
2987         if (uuid == NULL)
2988                 uuid = generate_uuid(conn TSRMLS_CC);
2989
2990         if (domain_flags & DOMAIN_FLAG_FEATURE_ACPI)
2991                 strcat(features, "<acpi/>");
2992         if (domain_flags & DOMAIN_FLAG_FEATURE_APIC)
2993                 strcat(features, "<apic/>");
2994         if (domain_flags & DOMAIN_FLAG_FEATURE_PAE)
2995                 strcat(features, "<pae/>");
2996
2997         if (arch == NULL) {
2998                 arch = connection_get_arch(conn TSRMLS_CC);
2999                 DPRINTF("%s: No architecture defined, got host arch of '%s'\n", __FUNCTION__, arch);
3000         }
3001
3002         if (access(iso_image, R_OK) != 0) {
3003                 DPRINTF("%s: Installation image %s doesn't exist\n", __FUNCTION__, iso_image);
3004                 return NULL;
3005         }
3006
3007         tmp = connection_get_domain_type(conn, arch TSRMLS_CC);
3008         if (tmp != NULL)
3009                 snprintf(type, sizeof(type), " type='%s'", tmp);
3010
3011         for (i = 0; i < numDisks; i++) {
3012                 char *disk = get_disk_xml(disks[i].size, disks[i].path, disks[i].driver, disks[i].bus, disks[i].dev, disks[i].flags TSRMLS_CC);
3013
3014                 if (disk != NULL)
3015                         strcat(disks_xml, disk);
3016
3017                 free(disk);
3018         }
3019
3020         for (i = 0; i < numNetworks; i++) {
3021                 char *network = get_network_xml(networks[i].mac, networks[i].network, networks[i].model);
3022
3023                 if (network != NULL)
3024                         strcat(networks_xml, network);
3025
3026                 free(network);
3027         }
3028
3029         if (step == 1)
3030                 snprintf(xml, sizeof(xml), "<domain%s>\n"
3031                                                                 "\t<name>%s</name>\n"
3032                                                                 "\t<currentMemory>%d</currentMemory>\n"
3033                                                                 "\t<memory>%d</memory>\n"
3034                                                                 "\t<uuid>%s</uuid>\n"
3035                                                                 "\t<os>\n"
3036                                                                 "\t\t<type arch='%s'>hvm</type>\n"
3037                                                                 "\t\t<boot dev='cdrom'/>\n"
3038                                                                 "\t\t<boot dev='hd'/>\n"
3039                                                                 "\t</os>\n"
3040                                                                 "\t<features>\n"
3041                                                                 "\t\t%s\n"
3042                                                                 "\t</features>\n"
3043                                                                 "\t<clock offset=\"%s\"/>\n"
3044                                                                 "\t<on_poweroff>destroy</on_poweroff>\n"
3045                                                                 "\t<on_reboot>destroy</on_reboot>\n"
3046                                                                 "\t<on_crash>destroy</on_crash>\n"
3047                                                                 "\t<vcpu>%d</vcpu>\n"
3048                                                                 "\t<devices>\n"
3049                                                                 "\t\t<emulator>%s</emulator>\n"
3050                                                                 "%s"
3051                                                                 "\t\t<disk type='file' device='cdrom'>\n"
3052                                                                 "\t\t\t<driver name='qemu' type='raw' />\n"
3053                                                                 "\t\t\t<source file='%s' />\n"
3054                                                                 "\t\t\t<target dev='hdc' bus='ide' />\n"
3055                                                                 "\t\t\t<readonly />\n"
3056                                                                 "\t\t</disk>\n"
3057                                                                 "%s"
3058                                                                 "\t\t<input type='mouse' bus='ps2' />\n"
3059                                                                 "\t\t<graphics type='vnc' port='-1' />\n"
3060                                                                 "\t\t<console type='pty' />\n"
3061                                                                 "%s"
3062                                                                 "\t\t<video>\n"
3063                                                                 "\t\t\t<model type='cirrus' />\n"
3064                                                                 "\t\t</video>\n"
3065                                                                 "\t</devices>\n"
3066                                                                 "</domain>",
3067                                                                 type, name, memMB * 1024, maxmemMB * 1024, uuid, arch, features,
3068                                                                 (domain_flags & DOMAIN_FLAG_CLOCK_LOCALTIME ? "localtime" : "utc"),
3069                                                                 vCpus, connection_get_emulator(conn, arch TSRMLS_CC), disks_xml, iso_image, networks_xml,
3070                                                                 (domain_flags & DOMAIN_FLAG_SOUND_AC97 ? "\t\t<sound model='ac97'/>\n" : "")
3071                                                                 );
3072         else
3073         if (step == 2)
3074                 snprintf(xml, sizeof(xml), "<domain%s>\n"
3075                                                                 "\t<name>%s</name>\n"
3076                                                                 "\t<currentMemory>%d</currentMemory>\n"
3077                                                                 "\t<memory>%d</memory>\n"
3078                                                                 "\t<uuid>%s</uuid>\n"
3079                                                                 "\t<os>\n"
3080                                                                 "\t\t<type arch='%s'>hvm</type>\n"
3081                                                                 "\t\t<boot dev='hd'/>\n"
3082                                                                 "\t</os>\n"
3083                                                                 "\t<features>\n"
3084                                                                 "\t\t%s\n"
3085                                                                 "\t</features>\n"
3086                                                                 "\t<clock offset=\"%s\"/>\n"
3087                                                                 "\t<on_poweroff>destroy</on_poweroff>\n"
3088                                                                 "\t<on_reboot>destroy</on_reboot>\n"
3089                                                                 "\t<on_crash>destroy</on_crash>\n"
3090                                                                 "\t<vcpu>%d</vcpu>\n"
3091                                                                 "\t<devices>\n"
3092                                                                 "\t\t<emulator>%s</emulator>\n"
3093                                                                 "%s"
3094                                                                 "\t\t<disk type='file' device='cdrom'>\n"
3095                                                                 "\t\t\t<driver name='qemu' type='raw' />\n"
3096                                                                 "\t\t\t<target dev='hdc' bus='ide' />\n"
3097                                                                 "\t\t\t<readonly />\n"
3098                                                                 "\t\t</disk>\n"
3099                                                                 "%s"
3100                                                                 "\t\t<input type='mouse' bus='ps2' />\n"
3101                                                                 "\t\t<graphics type='vnc' port='-1' />\n"
3102                                                                 "\t\t<console type='pty' />\n"
3103                                                                 "%s"
3104                                                                 "\t\t<video>\n"
3105                                                                 "\t\t\t<model type='cirrus' />\n"
3106                                                                 "\t\t</video>\n"
3107                                                                 "\t</devices>\n"
3108                                                                 "</domain>",
3109                                                                 type, name, memMB * 1024, maxmemMB * 1024, uuid, arch, features,
3110                                                                 (domain_flags & DOMAIN_FLAG_CLOCK_LOCALTIME ? "localtime" : "utc"),
3111                                                                 vCpus, connection_get_emulator(conn, arch TSRMLS_CC), disks_xml, networks_xml,
3112                                                                 (domain_flags & DOMAIN_FLAG_SOUND_AC97 ? "\t\t<sound model='ac97'/>\n" : "")
3113                                                                 );
3114
3115         return (strlen(xml) > 0) ? strdup(xml) : NULL;
3116 }
3117
3118 /* Domain functions */
3119
3120 /*
3121         Function name:  libvirt_domain_get_counts
3122         Since version:  0.4.1(-1)
3123         Description:    Function is getting domain counts for all, active and inactive domains
3124         Arguments:      @conn [resource]: libvirt connection resource from libvirt_connect()
3125         Returns:        array of total, active and inactive (but defined) domain counts
3126 */
3127 PHP_FUNCTION(libvirt_domain_get_counts)
3128 {
3129         php_libvirt_connection *conn=NULL;
3130         zval *zconn;
3131         int count_defined;
3132         int count_active;
3133
3134         GET_CONNECTION_FROM_ARGS("r",&zconn);
3135