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