1 /*
2  * esx_vi.c: client for the VMware VI API 2.5 to manage ESX hosts
3  *
4  * Copyright (C) 2010-2012 Red Hat, Inc.
5  * Copyright (C) 2009-2012, 2014 Matthias Bolte <matthias.bolte@googlemail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library.  If not, see
19  * <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include <config.h>
24 
25 #include <libxml/parser.h>
26 #include <libxml/xpathInternals.h>
27 
28 #include "virbuffer.h"
29 #include "viralloc.h"
30 #include "virlog.h"
31 #include "viruuid.h"
32 #include "vmx.h"
33 #include "virxml.h"
34 #include "esx_vi.h"
35 #include "esx_vi_methods.h"
36 #include "esx_util.h"
37 #include "virstring.h"
38 #include "virutil.h"
39 
40 #define VIR_FROM_THIS VIR_FROM_ESX
41 
42 VIR_LOG_INIT("esx.esx_vi");
43 
44 #define ESX_VI__SOAP__RESPONSE_XPATH(_type) \
45     ((char *)"/soapenv:Envelope/soapenv:Body/" \
46                "vim:"_type"Response/vim:returnval")
47 
48 
49 
50 #define ESX_VI__TEMPLATE__ALLOC(_type) \
51     int \
52     esxVI_##_type##_Alloc(esxVI_##_type **ptrptr) \
53     { \
54         ESX_VI_CHECK_ARG_LIST(ptrptr); \
55  \
56         *ptrptr = g_new0(esxVI_##_type, 1); \
57         return 0; \
58     }
59 
60 
61 
62 #define ESX_VI__TEMPLATE__FREE(_type, _body) \
63     void \
64     esxVI_##_type##_Free(esxVI_##_type **ptrptr) \
65     { \
66         esxVI_##_type *item G_GNUC_UNUSED; \
67  \
68         if (!ptrptr || !(*ptrptr)) { \
69             return; \
70         } \
71  \
72         item = *ptrptr; \
73  \
74         _body \
75  \
76         g_clear_pointer(ptrptr, g_free); \
77     }
78 
79 
80 
81 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
82  * CURL
83  */
84 
85 /* esxVI_CURL_Alloc */
86 ESX_VI__TEMPLATE__ALLOC(CURL)
87 
88 /* esxVI_CURL_Free */
89 ESX_VI__TEMPLATE__FREE(CURL,
90 {
91     esxVI_SharedCURL *shared = item->shared;
92     esxVI_MultiCURL *multi = item->multi;
93 
94     if (shared) {
95         esxVI_SharedCURL_Remove(shared, item);
96 
97         if (shared->count == 0)
98             esxVI_SharedCURL_Free(&shared);
99     }
100 
101     if (multi) {
102         esxVI_MultiCURL_Remove(multi, item);
103 
104         if (multi->count == 0)
105             esxVI_MultiCURL_Free(&multi);
106     }
107 
108     if (item->handle)
109         curl_easy_cleanup(item->handle);
110 
111     if (item->headers)
112         curl_slist_free_all(item->headers);
113 
114     virMutexDestroy(&item->lock);
115 })
116 
117 static size_t
esxVI_CURL_ReadString(char * data,size_t size,size_t nmemb,void * userdata)118 esxVI_CURL_ReadString(char *data, size_t size, size_t nmemb, void *userdata)
119 {
120     const char *content = *(const char **)userdata;
121     size_t available = 0;
122     size_t requested = size * nmemb;
123 
124     if (!content)
125         return 0;
126 
127     available = strlen(content);
128 
129     if (available == 0)
130         return 0;
131 
132     if (requested > available)
133         requested = available;
134 
135     memcpy(data, content, requested);
136 
137     *(const char **)userdata = content + requested;
138 
139     return requested;
140 }
141 
142 static size_t
esxVI_CURL_WriteBuffer(char * data,size_t size,size_t nmemb,void * userdata)143 esxVI_CURL_WriteBuffer(char *data, size_t size, size_t nmemb, void *userdata)
144 {
145     virBuffer *buffer = userdata;
146 
147     if (buffer) {
148         /*
149          * Using a virBuffer to store the download data limits the downloadable
150          * size. This is no problem as esxVI_CURL_Download and esxVI_CURL_Perform
151          * are meant to download small things such as VMX files, VMDK metadata
152          * files and SOAP responses.
153          */
154         if (size * nmemb > INT32_MAX / 2 - virBufferUse(buffer))
155             return 0;
156 
157         virBufferAdd(buffer, data, size * nmemb);
158 
159         return size * nmemb;
160     }
161 
162     return 0;
163 }
164 
165 #define ESX_VI__CURL__ENABLE_DEBUG_OUTPUT 0
166 
167 #if ESX_VI__CURL__ENABLE_DEBUG_OUTPUT
168 static int
esxVI_CURL_Debug(CURL * curl G_GNUC_UNUSED,curl_infotype type,char * info,size_t size,void * userdata G_GNUC_UNUSED)169 esxVI_CURL_Debug(CURL *curl G_GNUC_UNUSED, curl_infotype type,
170                  char *info, size_t size, void *userdata G_GNUC_UNUSED)
171 {
172     g_autofree char *buffer = NULL;
173 
174     /*
175      * The libcurl documentation says:
176      *
177      *    The data pointed to by the char * passed to this function WILL NOT
178      *    be zero terminated, but will be exactly of the size as told by the
179      *    size_t argument.
180      *
181      * To handle this properly in order to pass the info string to VIR_DEBUG
182      * a zero terminated copy of the info string has to be allocated.
183      */
184     buffer = g_new0(char, size + 1);
185 
186     memcpy(buffer, info, size);
187     buffer[size] = '\0';
188 
189     switch (type) {
190       case CURLINFO_TEXT:
191         if (size > 0 && buffer[size - 1] == '\n')
192             buffer[size - 1] = '\0';
193 
194         VIR_DEBUG("CURLINFO_TEXT [[[[%s]]]]", buffer);
195         break;
196 
197       case CURLINFO_HEADER_IN:
198         VIR_DEBUG("CURLINFO_HEADER_IN [[[[%s]]]]", buffer);
199         break;
200 
201       case CURLINFO_HEADER_OUT:
202         VIR_DEBUG("CURLINFO_HEADER_OUT [[[[%s]]]]", buffer);
203         break;
204 
205       case CURLINFO_DATA_IN:
206       case CURLINFO_SSL_DATA_IN:
207         VIR_DEBUG("CURLINFO_DATA_IN [[[[%s]]]]", buffer);
208         break;
209 
210       case CURLINFO_DATA_OUT:
211       case CURLINFO_SSL_DATA_OUT:
212         VIR_DEBUG("CURLINFO_DATA_OUT [[[[%s]]]]", buffer);
213         break;
214 
215       case CURLINFO_END:
216         VIR_DEBUG("CURLINFO_END [[[[%s]]]]", buffer);
217         break;
218 
219       default:
220         VIR_DEBUG("unknown");
221         break;
222     }
223 
224     return 0;
225 }
226 #endif
227 
228 static int
esxVI_CURL_Perform(esxVI_CURL * curl,const char * url)229 esxVI_CURL_Perform(esxVI_CURL *curl, const char *url)
230 {
231     CURLcode errorCode;
232     long responseCode = 0;
233     const char *redirectUrl = NULL;
234 
235     errorCode = curl_easy_perform(curl->handle);
236 
237     if (errorCode != CURLE_OK) {
238         virReportError(VIR_ERR_INTERNAL_ERROR,
239                        _("curl_easy_perform() returned an error: %s (%d) : %s"),
240                        curl_easy_strerror(errorCode), errorCode, curl->error);
241         return -1;
242     }
243 
244     errorCode = curl_easy_getinfo(curl->handle, CURLINFO_RESPONSE_CODE,
245                                   &responseCode);
246 
247     if (errorCode != CURLE_OK) {
248         virReportError(VIR_ERR_INTERNAL_ERROR,
249                        _("curl_easy_getinfo(CURLINFO_RESPONSE_CODE) returned an "
250                          "error: %s (%d) : %s"), curl_easy_strerror(errorCode),
251                        errorCode, curl->error);
252         return -1;
253     }
254 
255     if (responseCode < 0) {
256         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
257                        _("curl_easy_getinfo(CURLINFO_RESPONSE_CODE) returned a "
258                          "negative response code"));
259         return -1;
260     }
261 
262     if (responseCode == 301) {
263         errorCode = curl_easy_getinfo(curl->handle, CURLINFO_REDIRECT_URL,
264                                       &redirectUrl);
265 
266         if (errorCode != CURLE_OK) {
267             virReportError(VIR_ERR_INTERNAL_ERROR,
268                            _("curl_easy_getinfo(CURLINFO_REDIRECT_URL) returned "
269                              "an error: %s (%d) : %s"),
270                            curl_easy_strerror(errorCode),
271                            errorCode, curl->error);
272         } else {
273             virReportError(VIR_ERR_INTERNAL_ERROR,
274                            _("The server redirects from '%s' to '%s'"), url,
275                            redirectUrl);
276         }
277 
278         return -1;
279     }
280 
281     return responseCode;
282 }
283 
284 int
esxVI_CURL_Connect(esxVI_CURL * curl,esxUtil_ParsedUri * parsedUri)285 esxVI_CURL_Connect(esxVI_CURL *curl, esxUtil_ParsedUri *parsedUri)
286 {
287     if (curl->handle) {
288         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid call"));
289         return -1;
290     }
291 
292     curl->handle = curl_easy_init();
293 
294     if (!curl->handle) {
295         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
296                        _("Could not initialize CURL"));
297         return -1;
298     }
299 
300     curl->headers = curl_slist_append(curl->headers,
301                                       "Content-Type: text/xml; charset=UTF-8");
302 
303     /*
304      * Add an empty expect header to stop CURL from waiting for a response code
305      * 100 (Continue) from the server before continuing the POST operation.
306      * Waiting for this response would slowdown each communication with the
307      * server by approx. 2 sec, because the server doesn't send the expected
308      * 100 (Continue) response and the wait times out resulting in wasting
309      * approx. 2 sec per POST operation.
310      */
311     curl->headers = curl_slist_append(curl->headers, "Expect:");
312 
313     if (!curl->headers) {
314         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
315                        _("Could not build CURL header list"));
316         return -1;
317     }
318 
319     curl_easy_setopt(curl->handle, CURLOPT_USERAGENT, "libvirt-esx");
320     curl_easy_setopt(curl->handle, CURLOPT_NOSIGNAL, 1);
321     curl_easy_setopt(curl->handle, CURLOPT_HEADER, 0);
322     curl_easy_setopt(curl->handle, CURLOPT_FOLLOWLOCATION, 0);
323     curl_easy_setopt(curl->handle, CURLOPT_SSL_VERIFYPEER,
324                      parsedUri->noVerify ? 0 : 1);
325     curl_easy_setopt(curl->handle, CURLOPT_SSL_VERIFYHOST,
326                      parsedUri->noVerify ? 0 : 2);
327     curl_easy_setopt(curl->handle, CURLOPT_COOKIEFILE, "");
328     curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->headers);
329     curl_easy_setopt(curl->handle, CURLOPT_READFUNCTION,
330                      esxVI_CURL_ReadString);
331     curl_easy_setopt(curl->handle, CURLOPT_WRITEFUNCTION,
332                      esxVI_CURL_WriteBuffer);
333     curl_easy_setopt(curl->handle, CURLOPT_ERRORBUFFER, curl->error);
334 #if ESX_VI__CURL__ENABLE_DEBUG_OUTPUT
335     curl_easy_setopt(curl->handle, CURLOPT_DEBUGFUNCTION, esxVI_CURL_Debug);
336     curl_easy_setopt(curl->handle, CURLOPT_VERBOSE, 1);
337 #endif
338 
339     if (parsedUri->proxy) {
340         curl_easy_setopt(curl->handle, CURLOPT_PROXY,
341                          parsedUri->proxy_hostname);
342         curl_easy_setopt(curl->handle, CURLOPT_PROXYTYPE,
343                          parsedUri->proxy_type);
344         curl_easy_setopt(curl->handle, CURLOPT_PROXYPORT,
345                          parsedUri->proxy_port);
346     }
347 
348     if (virMutexInit(&curl->lock) < 0) {
349         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
350                        _("Could not initialize CURL mutex"));
351         return -1;
352     }
353 
354     return 0;
355 }
356 
357 int
esxVI_CURL_Download(esxVI_CURL * curl,const char * url,char ** content,unsigned long long offset,unsigned long long * length)358 esxVI_CURL_Download(esxVI_CURL *curl, const char *url, char **content,
359                     unsigned long long offset, unsigned long long *length)
360 {
361     g_autofree char *range = NULL;
362     g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
363     int responseCode = 0;
364 
365     ESX_VI_CHECK_ARG_LIST(content);
366 
367     if (length && *length > 0) {
368         /*
369          * Using a virBuffer to store the download data limits the downloadable
370          * size. This is no problem as esxVI_CURL_Download is meant to download
371          * small things such as VMX of VMDK metadata files.
372          */
373         if (*length > INT32_MAX / 2) {
374             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
375                            _("Download length it too large"));
376             return -1;
377         }
378 
379         range = g_strdup_printf("%llu-%llu", offset, offset + *length - 1);
380     } else if (offset > 0) {
381         range = g_strdup_printf("%llu-", offset);
382     }
383 
384     virMutexLock(&curl->lock);
385 
386     curl_easy_setopt(curl->handle, CURLOPT_URL, url);
387     curl_easy_setopt(curl->handle, CURLOPT_RANGE, range);
388     curl_easy_setopt(curl->handle, CURLOPT_WRITEDATA, &buffer);
389     curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 0);
390     curl_easy_setopt(curl->handle, CURLOPT_HTTPGET, 1);
391 
392     responseCode = esxVI_CURL_Perform(curl, url);
393 
394     virMutexUnlock(&curl->lock);
395 
396     if (responseCode < 0) {
397         return -1;
398     } else if (responseCode != 200 && responseCode != 206) {
399         virReportError(VIR_ERR_INTERNAL_ERROR,
400                        _("HTTP response code %d for download from '%s'"),
401                        responseCode, url);
402         return -1;
403     }
404 
405     if (length)
406         *length = virBufferUse(&buffer);
407 
408     *content = virBufferContentAndReset(&buffer);
409 
410     if (!(*content))
411         return -1;
412 
413     return 0;
414 }
415 
416 int
esxVI_CURL_Upload(esxVI_CURL * curl,const char * url,const char * content)417 esxVI_CURL_Upload(esxVI_CURL *curl, const char *url, const char *content)
418 {
419     int responseCode = 0;
420 
421     if (!content) {
422         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
423         return -1;
424     }
425 
426     virMutexLock(&curl->lock);
427 
428     curl_easy_setopt(curl->handle, CURLOPT_URL, url);
429     curl_easy_setopt(curl->handle, CURLOPT_RANGE, NULL);
430     curl_easy_setopt(curl->handle, CURLOPT_READDATA, &content);
431     curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1);
432     curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, strlen(content));
433 
434     responseCode = esxVI_CURL_Perform(curl, url);
435 
436     virMutexUnlock(&curl->lock);
437 
438     if (responseCode < 0) {
439         return -1;
440     } else if (responseCode != 200 && responseCode != 201) {
441         virReportError(VIR_ERR_INTERNAL_ERROR,
442                        _("HTTP response code %d for upload to '%s'"),
443                        responseCode, url);
444         return -1;
445     }
446 
447     return 0;
448 }
449 
450 
451 
452 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
453  * SharedCURL
454  */
455 
456 static void
esxVI_SharedCURL_Lock(CURL * handle G_GNUC_UNUSED,curl_lock_data data,curl_lock_access access_ G_GNUC_UNUSED,void * userptr)457 esxVI_SharedCURL_Lock(CURL *handle G_GNUC_UNUSED, curl_lock_data data,
458                       curl_lock_access access_ G_GNUC_UNUSED, void *userptr)
459 {
460     size_t i;
461     esxVI_SharedCURL *shared = userptr;
462 
463     switch ((int)data) {
464       case CURL_LOCK_DATA_SHARE:
465         i = 0;
466         break;
467 
468       case CURL_LOCK_DATA_COOKIE:
469         i = 1;
470         break;
471 
472       case CURL_LOCK_DATA_DNS:
473         i = 2;
474         break;
475 
476       default:
477         VIR_ERROR(_("Trying to lock unknown SharedCURL lock %d"), (int)data);
478         return;
479     }
480 
481     virMutexLock(&shared->locks[i]);
482 }
483 
484 static void
esxVI_SharedCURL_Unlock(CURL * handle G_GNUC_UNUSED,curl_lock_data data,void * userptr)485 esxVI_SharedCURL_Unlock(CURL *handle G_GNUC_UNUSED, curl_lock_data data,
486                         void *userptr)
487 {
488     size_t i;
489     esxVI_SharedCURL *shared = userptr;
490 
491     switch ((int)data) {
492       case CURL_LOCK_DATA_SHARE:
493         i = 0;
494         break;
495 
496       case CURL_LOCK_DATA_COOKIE:
497         i = 1;
498         break;
499 
500       case CURL_LOCK_DATA_DNS:
501         i = 2;
502         break;
503 
504       default:
505         VIR_ERROR(_("Trying to unlock unknown SharedCURL lock %d"), (int)data);
506         return;
507     }
508 
509     virMutexUnlock(&shared->locks[i]);
510 }
511 
512 /* esxVI_SharedCURL_Alloc */
513 ESX_VI__TEMPLATE__ALLOC(SharedCURL)
514 
515 /* esxVI_SharedCURL_Free */
516 ESX_VI__TEMPLATE__FREE(SharedCURL,
517 {
518     size_t i;
519 
520     if (item->count > 0) {
521         /* Better leak than crash */
522         VIR_ERROR(_("Trying to free SharedCURL object that is still in use"));
523         return;
524     }
525 
526     if (item->handle)
527         curl_share_cleanup(item->handle);
528 
529     for (i = 0; i < G_N_ELEMENTS(item->locks); ++i)
530         virMutexDestroy(&item->locks[i]);
531 })
532 
533 int
esxVI_SharedCURL_Add(esxVI_SharedCURL * shared,esxVI_CURL * curl)534 esxVI_SharedCURL_Add(esxVI_SharedCURL *shared, esxVI_CURL *curl)
535 {
536     size_t i;
537 
538     if (!curl->handle) {
539         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
540                        _("Cannot share uninitialized CURL handle"));
541         return -1;
542     }
543 
544     if (curl->shared) {
545         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
546                        _("Cannot share CURL handle that is already shared"));
547         return -1;
548     }
549 
550     if (!shared->handle) {
551         shared->handle = curl_share_init();
552 
553         if (!shared->handle) {
554             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
555                            _("Could not initialize CURL (share)"));
556             return -1;
557         }
558 
559         curl_share_setopt(shared->handle, CURLSHOPT_LOCKFUNC,
560                           esxVI_SharedCURL_Lock);
561         curl_share_setopt(shared->handle, CURLSHOPT_UNLOCKFUNC,
562                           esxVI_SharedCURL_Unlock);
563         curl_share_setopt(shared->handle, CURLSHOPT_USERDATA, shared);
564         curl_share_setopt(shared->handle, CURLSHOPT_SHARE,
565                           CURL_LOCK_DATA_COOKIE);
566         curl_share_setopt(shared->handle, CURLSHOPT_SHARE,
567                           CURL_LOCK_DATA_DNS);
568 
569         for (i = 0; i < G_N_ELEMENTS(shared->locks); ++i) {
570             if (virMutexInit(&shared->locks[i]) < 0) {
571                 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
572                                _("Could not initialize a CURL (share) mutex"));
573                 return -1;
574             }
575         }
576     }
577 
578     virMutexLock(&curl->lock);
579 
580     curl_easy_setopt(curl->handle, CURLOPT_SHARE, shared->handle);
581 
582     curl->shared = shared;
583     ++shared->count;
584 
585     virMutexUnlock(&curl->lock);
586 
587     return 0;
588 }
589 
590 int
esxVI_SharedCURL_Remove(esxVI_SharedCURL * shared,esxVI_CURL * curl)591 esxVI_SharedCURL_Remove(esxVI_SharedCURL *shared, esxVI_CURL *curl)
592 {
593     if (!curl->handle) {
594         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
595                        _("Cannot unshare uninitialized CURL handle"));
596         return -1;
597     }
598 
599     if (!curl->shared) {
600         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
601                        _("Cannot unshare CURL handle that is not shared"));
602         return -1;
603     }
604 
605     if (curl->shared != shared) {
606         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("CURL (share) mismatch"));
607         return -1;
608     }
609 
610     virMutexLock(&curl->lock);
611 
612     curl_easy_setopt(curl->handle, CURLOPT_SHARE, NULL);
613 
614     curl->shared = NULL;
615     --shared->count;
616 
617     virMutexUnlock(&curl->lock);
618 
619     return 0;
620 }
621 
622 
623 
624 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
625  * MultiCURL
626  */
627 
628 
629 /* esxVI_MultiCURL_Alloc */
630 ESX_VI__TEMPLATE__ALLOC(MultiCURL)
631 
632 /* esxVI_MultiCURL_Free */
633 ESX_VI__TEMPLATE__FREE(MultiCURL,
634 {
635     if (item->count > 0) {
636         /* Better leak than crash */
637         VIR_ERROR(_("Trying to free MultiCURL object that is still in use"));
638         return;
639     }
640 
641     if (item->handle)
642         curl_multi_cleanup(item->handle);
643 })
644 
645 int
esxVI_MultiCURL_Add(esxVI_MultiCURL * multi,esxVI_CURL * curl)646 esxVI_MultiCURL_Add(esxVI_MultiCURL *multi, esxVI_CURL *curl)
647 {
648     if (!curl->handle) {
649         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
650                        _("Cannot add uninitialized CURL handle to a multi handle"));
651         return -1;
652     }
653 
654     if (curl->multi) {
655         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
656                        _("Cannot add CURL handle to a multi handle twice"));
657         return -1;
658     }
659 
660     if (!multi->handle) {
661         multi->handle = curl_multi_init();
662 
663         if (!multi->handle) {
664             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
665                            _("Could not initialize CURL (multi)"));
666             return -1;
667         }
668 
669     }
670 
671     virMutexLock(&curl->lock);
672 
673     curl_multi_add_handle(multi->handle, curl->handle);
674 
675     curl->multi = multi;
676     ++multi->count;
677 
678     virMutexUnlock(&curl->lock);
679 
680     return 0;
681 }
682 
683 int
esxVI_MultiCURL_Remove(esxVI_MultiCURL * multi,esxVI_CURL * curl)684 esxVI_MultiCURL_Remove(esxVI_MultiCURL *multi, esxVI_CURL *curl)
685 {
686     if (!curl->handle) {
687         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
688                        _("Cannot remove uninitialized CURL handle from a "
689                          "multi handle"));
690         return -1;
691     }
692 
693     if (!curl->multi) {
694         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
695                        _("Cannot remove CURL handle from a multi handle when it "
696                          "wasn't added before"));
697         return -1;
698     }
699 
700     if (curl->multi != multi) {
701         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("CURL (multi) mismatch"));
702         return -1;
703     }
704 
705     virMutexLock(&curl->lock);
706 
707     curl_multi_remove_handle(multi->handle, curl->handle);
708 
709     curl->multi = NULL;
710     --multi->count;
711 
712     virMutexUnlock(&curl->lock);
713 
714     return 0;
715 }
716 
717 
718 int
esxVI_MultiCURL_Wait(esxVI_MultiCURL * multi,int * runningHandles)719 esxVI_MultiCURL_Wait(esxVI_MultiCURL *multi, int *runningHandles)
720 {
721     long timeout = -1;
722     CURLMcode errorCode;
723 
724     curl_multi_timeout(multi->handle, &timeout);
725 
726     if (timeout < 0)
727         timeout = 1000; /* default to 1 sec timeout */
728 
729     errorCode = curl_multi_wait(multi->handle, NULL, 0, timeout, NULL);
730 
731     if (errorCode != CURLM_OK) {
732         virReportError(VIR_ERR_INTERNAL_ERROR,
733                        _("Could not wait for transfer: %s (%d)"),
734                        curl_multi_strerror(errorCode), errorCode);
735         return -1;
736     }
737 
738     return esxVI_MultiCURL_Perform(multi, runningHandles);
739 }
740 
741 int
esxVI_MultiCURL_Perform(esxVI_MultiCURL * multi,int * runningHandles)742 esxVI_MultiCURL_Perform(esxVI_MultiCURL *multi, int *runningHandles)
743 {
744     CURLMcode errorCode;
745 
746     do {
747         errorCode = curl_multi_perform(multi->handle, runningHandles);
748     } while (errorCode == CURLM_CALL_MULTI_PERFORM);
749 
750     if (errorCode != CURLM_OK) {
751         virReportError(VIR_ERR_INTERNAL_ERROR,
752                        _("Could not transfer data: %s (%d)"),
753                        curl_multi_strerror(errorCode), errorCode);
754         return -1;
755     }
756 
757     return 0;
758 }
759 
760 /* Returns -1 on error, 0 if there is no DONE message, 1 if there is a DONE message */
761 int
esxVI_MultiCURL_CheckFirstMessage(esxVI_MultiCURL * multi,long * responseCode,CURLcode * errorCode)762 esxVI_MultiCURL_CheckFirstMessage(esxVI_MultiCURL *multi, long *responseCode,
763                                   CURLcode *errorCode)
764 {
765     int messagesInQueue;
766     CURLMsg* msg = curl_multi_info_read(multi->handle, &messagesInQueue);
767 
768     *responseCode = 0;
769 
770     if (!msg || msg->msg != CURLMSG_DONE)
771         return 0;
772 
773     *errorCode = msg->data.result;
774 
775     if (*errorCode != CURLE_OK)
776         return -1;
777 
778     curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, responseCode);
779 
780     return 1;
781 }
782 
783 
784 
785 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
786  * Context
787  */
788 
789 /* esxVI_Context_Alloc */
790 ESX_VI__TEMPLATE__ALLOC(Context)
791 
792 /* esxVI_Context_Free */
793 ESX_VI__TEMPLATE__FREE(Context,
794 {
795     if (item->sessionLock)
796         virMutexDestroy(item->sessionLock);
797 
798     esxVI_CURL_Free(&item->curl);
799     g_free(item->url);
800     g_free(item->ipAddress);
801     g_free(item->username);
802     g_free(item->password);
803     esxVI_ServiceContent_Free(&item->service);
804     esxVI_UserSession_Free(&item->session);
805     g_free(item->sessionLock);
806     esxVI_Datacenter_Free(&item->datacenter);
807     g_free(item->datacenterPath);
808     esxVI_ComputeResource_Free(&item->computeResource);
809     g_free(item->computeResourcePath);
810     esxVI_HostSystem_Free(&item->hostSystem);
811     g_free(item->hostSystemName);
812     esxVI_SelectionSpec_Free(&item->selectSet_folderToChildEntity);
813     esxVI_SelectionSpec_Free(&item->selectSet_hostSystemToParent);
814     esxVI_SelectionSpec_Free(&item->selectSet_hostSystemToVm);
815     esxVI_SelectionSpec_Free(&item->selectSet_hostSystemToDatastore);
816     esxVI_SelectionSpec_Free(&item->selectSet_computeResourceToHost);
817     esxVI_SelectionSpec_Free(&item->selectSet_computeResourceToParentToParent);
818     esxVI_SelectionSpec_Free(&item->selectSet_datacenterToNetwork);
819 })
820 
821 int
esxVI_Context_Connect(esxVI_Context * ctx,const char * url,const char * ipAddress,const char * username,const char * password,esxUtil_ParsedUri * parsedUri)822 esxVI_Context_Connect(esxVI_Context *ctx, const char *url,
823                       const char *ipAddress, const char *username,
824                       const char *password, esxUtil_ParsedUri *parsedUri)
825 {
826     g_autofree char *escapedPassword = NULL;
827 
828     if (!ctx || !url || !ipAddress || !username ||
829         !password || ctx->url || ctx->service || ctx->curl) {
830         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
831         return -1;
832     }
833 
834     escapedPassword = esxUtil_EscapeForXml(password);
835 
836     if (!escapedPassword) {
837         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
838                        _("Failed to escape password for XML"));
839         return -1;
840     }
841 
842     if (esxVI_CURL_Alloc(&ctx->curl) < 0 ||
843         esxVI_CURL_Connect(ctx->curl, parsedUri) < 0) {
844         return -1;
845     }
846 
847     ctx->url = g_strdup(url);
848     ctx->ipAddress = g_strdup(ipAddress);
849     ctx->username = g_strdup(username);
850     ctx->password = g_strdup(password);
851 
852     ctx->sessionLock = g_new0(virMutex, 1);
853 
854 
855     if (virMutexInit(ctx->sessionLock) < 0) {
856         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
857                        _("Could not initialize session mutex"));
858         return -1;
859     }
860 
861     if (esxVI_RetrieveServiceContent(ctx, &ctx->service) < 0)
862         return -1;
863 
864     if (STRNEQ(ctx->service->about->apiType, "HostAgent") &&
865         STRNEQ(ctx->service->about->apiType, "VirtualCenter")) {
866         virReportError(VIR_ERR_INTERNAL_ERROR,
867                        _("Expecting VI API type 'HostAgent' or 'VirtualCenter' "
868                          "but found '%s'"), ctx->service->about->apiType);
869         return -1;
870     }
871 
872     if (virParseVersionString(ctx->service->about->apiVersion,
873                               &ctx->apiVersion, true) < 0) {
874         virReportError(VIR_ERR_INTERNAL_ERROR,
875                        _("Could not parse VI API version '%s'"),
876                        ctx->service->about->apiVersion);
877         return -1;
878     }
879 
880     if (ctx->apiVersion < 1000000 * 2 + 1000 * 5 /* 2.5 */) {
881         virReportError(VIR_ERR_INTERNAL_ERROR,
882                        _("Minimum supported %s version is %s but found version '%s'"),
883                        "VI API", "2.5", ctx->service->about->apiVersion);
884         return -1;
885     }
886 
887     if (virParseVersionString(ctx->service->about->version,
888                               &ctx->productVersion, true) < 0) {
889         virReportError(VIR_ERR_INTERNAL_ERROR,
890                        _("Could not parse product version '%s'"),
891                        ctx->service->about->version);
892         return -1;
893     }
894 
895     if (STREQ(ctx->service->about->productLineId, "gsx")) {
896         if (ctx->productVersion < 1000000 * 2 + 1000 * 0 /* 2.0 */) {
897             virReportError(VIR_ERR_INTERNAL_ERROR,
898                            _("Minimum supported %s version is %s but found version '%s'"),
899                            esxVI_ProductLineToDisplayName(esxVI_ProductLine_GSX),
900                            "2.0", ctx->service->about->version);
901             return -1;
902         }
903 
904         ctx->productLine = esxVI_ProductLine_GSX;
905     } else if (STREQ(ctx->service->about->productLineId, "esx") ||
906                STREQ(ctx->service->about->productLineId, "embeddedEsx")) {
907         if (ctx->productVersion < 1000000 * 3 + 1000 * 5 /* 3.5 */) {
908             virReportError(VIR_ERR_INTERNAL_ERROR,
909                            _("Minimum supported %s version is %s but found version '%s'"),
910                            esxVI_ProductLineToDisplayName(esxVI_ProductLine_ESX),
911                            "3.5", ctx->service->about->version);
912             return -1;
913         }
914 
915         ctx->productLine = esxVI_ProductLine_ESX;
916     } else if (STREQ(ctx->service->about->productLineId, "vpx")) {
917         if (ctx->productVersion < 1000000 * 2 + 1000 * 5 /* 2.5 */) {
918             virReportError(VIR_ERR_INTERNAL_ERROR,
919                            _("Minimum supported %s version is %s but found version '%s'"),
920                            esxVI_ProductLineToDisplayName(esxVI_ProductLine_VPX),
921                            "2.5", ctx->service->about->version);
922             return -1;
923         }
924 
925         ctx->productLine = esxVI_ProductLine_VPX;
926     } else {
927         virReportError(VIR_ERR_INTERNAL_ERROR,
928                        _("Expecting product 'gsx' or 'esx' or 'embeddedEsx' "
929                          "or 'vpx' but found '%s'"),
930                        ctx->service->about->productLineId);
931         return -1;
932     }
933 
934     if (ctx->productLine == esxVI_ProductLine_ESX) {
935         /*
936          * FIXME: Actually this should be detected by really calling
937          * QueryVirtualDiskUuid and checking if a NotImplemented fault is
938          * returned. But currently we don't deserialized the details of a
939          * possible fault and therefore we don't know if the fault was a
940          * NotImplemented fault or not.
941          */
942         ctx->hasQueryVirtualDiskUuid = true;
943     }
944 
945     if (ctx->productLine == esxVI_ProductLine_VPX)
946         ctx->hasSessionIsActive = true;
947 
948 
949 
950     if (esxVI_Login(ctx, username, escapedPassword, NULL, &ctx->session) < 0 ||
951         esxVI_BuildSelectSetCollection(ctx) < 0) {
952         return -1;
953     }
954 
955     return 0;
956 }
957 
958 int
esxVI_Context_LookupManagedObjects(esxVI_Context * ctx)959 esxVI_Context_LookupManagedObjects(esxVI_Context *ctx)
960 {
961     /* Lookup Datacenter */
962     if (esxVI_LookupDatacenter(ctx, NULL, ctx->service->rootFolder, NULL,
963                                &ctx->datacenter,
964                                esxVI_Occurrence_RequiredItem) < 0) {
965         return -1;
966     }
967 
968     ctx->datacenterPath = g_strdup(ctx->datacenter->name);
969 
970     /* Lookup (Cluster)ComputeResource */
971     if (esxVI_LookupComputeResource(ctx, NULL, ctx->datacenter->hostFolder,
972                                     NULL, &ctx->computeResource,
973                                     esxVI_Occurrence_RequiredItem) < 0) {
974         return -1;
975     }
976 
977     if (!ctx->computeResource->resourcePool) {
978         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
979                        _("Could not retrieve resource pool"));
980         return -1;
981     }
982 
983     ctx->computeResourcePath = g_strdup(ctx->computeResource->name);
984 
985     /* Lookup HostSystem */
986     if (esxVI_LookupHostSystem(ctx, NULL, ctx->computeResource->_reference,
987                                NULL, &ctx->hostSystem,
988                                esxVI_Occurrence_RequiredItem) < 0) {
989         return -1;
990     }
991 
992     ctx->hostSystemName = g_strdup(ctx->hostSystem->name);
993 
994     return 0;
995 }
996 
997 int
esxVI_Context_LookupManagedObjectsByPath(esxVI_Context * ctx,const char * path)998 esxVI_Context_LookupManagedObjectsByPath(esxVI_Context *ctx, const char *path)
999 {
1000     int result = -1;
1001     g_autofree char *tmp = NULL;
1002     char *saveptr = NULL;
1003     char *previousItem = NULL;
1004     char *item = NULL;
1005     g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
1006     esxVI_ManagedObjectReference *root = NULL;
1007     esxVI_Folder *folder = NULL;
1008 
1009     tmp = g_strdup(path);
1010 
1011     /* Lookup Datacenter */
1012     item = strtok_r(tmp, "/", &saveptr);
1013 
1014     if (!item) {
1015         virReportError(VIR_ERR_INVALID_ARG,
1016                        _("Path '%s' does not specify a datacenter"), path);
1017         goto cleanup;
1018     }
1019 
1020     root = ctx->service->rootFolder;
1021 
1022     while (!ctx->datacenter && item) {
1023         esxVI_Folder_Free(&folder);
1024 
1025         /* Try to lookup item as a folder */
1026         if (esxVI_LookupFolder(ctx, item, root, NULL, &folder,
1027                                esxVI_Occurrence_OptionalItem) < 0) {
1028             goto cleanup;
1029         }
1030 
1031         if (folder) {
1032             /* It's a folder, use it as new lookup root */
1033             if (root != ctx->service->rootFolder)
1034                 esxVI_ManagedObjectReference_Free(&root);
1035 
1036             root = folder->_reference;
1037             folder->_reference = NULL;
1038         } else {
1039             /* Try to lookup item as a datacenter */
1040             if (esxVI_LookupDatacenter(ctx, item, root, NULL, &ctx->datacenter,
1041                                        esxVI_Occurrence_OptionalItem) < 0) {
1042                 goto cleanup;
1043             }
1044         }
1045 
1046         /* Build datacenter path */
1047         if (virBufferUse(&buffer) > 0)
1048             virBufferAddChar(&buffer, '/');
1049 
1050         virBufferAdd(&buffer, item, -1);
1051 
1052         previousItem = item;
1053         item = strtok_r(NULL, "/", &saveptr);
1054     }
1055 
1056     if (!ctx->datacenter) {
1057         virReportError(VIR_ERR_INTERNAL_ERROR,
1058                        _("Could not find datacenter specified in '%s'"), path);
1059         goto cleanup;
1060     }
1061 
1062     ctx->datacenterPath = virBufferContentAndReset(&buffer);
1063 
1064     /* Lookup (Cluster)ComputeResource */
1065     if (!item) {
1066         virReportError(VIR_ERR_INVALID_ARG,
1067                        _("Path '%s' does not specify a compute resource"), path);
1068         goto cleanup;
1069     }
1070 
1071     if (root != ctx->service->rootFolder)
1072         esxVI_ManagedObjectReference_Free(&root);
1073 
1074     root = ctx->datacenter->hostFolder;
1075 
1076     while (!ctx->computeResource && item) {
1077         esxVI_Folder_Free(&folder);
1078 
1079         /* Try to lookup item as a folder */
1080         if (esxVI_LookupFolder(ctx, item, root, NULL, &folder,
1081                                esxVI_Occurrence_OptionalItem) < 0) {
1082             goto cleanup;
1083         }
1084 
1085         if (folder) {
1086             /* It's a folder, use it as new lookup root */
1087             if (root != ctx->datacenter->hostFolder)
1088                 esxVI_ManagedObjectReference_Free(&root);
1089 
1090             root = folder->_reference;
1091             folder->_reference = NULL;
1092         } else {
1093             /* Try to lookup item as a compute resource */
1094             if (esxVI_LookupComputeResource(ctx, item, root, NULL,
1095                                             &ctx->computeResource,
1096                                             esxVI_Occurrence_OptionalItem) < 0) {
1097                 goto cleanup;
1098             }
1099         }
1100 
1101         /* Build compute resource path */
1102         if (virBufferUse(&buffer) > 0)
1103             virBufferAddChar(&buffer, '/');
1104 
1105         virBufferAdd(&buffer, item, -1);
1106 
1107         previousItem = item;
1108         item = strtok_r(NULL, "/", &saveptr);
1109     }
1110 
1111     if (!ctx->computeResource) {
1112         virReportError(VIR_ERR_INTERNAL_ERROR,
1113                        _("Could not find compute resource specified in '%s'"),
1114                        path);
1115         goto cleanup;
1116     }
1117 
1118     if (!ctx->computeResource->resourcePool) {
1119         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1120                        _("Could not retrieve resource pool"));
1121         goto cleanup;
1122     }
1123 
1124     ctx->computeResourcePath = virBufferContentAndReset(&buffer);
1125 
1126     /* Lookup HostSystem */
1127     if (STREQ(ctx->computeResource->_reference->type,
1128               "ClusterComputeResource")) {
1129         if (!item) {
1130             virReportError(VIR_ERR_INVALID_ARG,
1131                            _("Path '%s' does not specify a host system"), path);
1132             goto cleanup;
1133         }
1134 
1135         /* The path specified a cluster, it has to specify a host system too */
1136         previousItem = item;
1137         item = strtok_r(NULL, "/", &saveptr);
1138     }
1139 
1140     if (item) {
1141         virReportError(VIR_ERR_INVALID_ARG,
1142                        _("Path '%s' ends with an excess item"), path);
1143         goto cleanup;
1144     }
1145 
1146     ctx->hostSystemName = g_strdup(previousItem);
1147 
1148     if (esxVI_LookupHostSystem(ctx, ctx->hostSystemName,
1149                                ctx->computeResource->_reference, NULL,
1150                                &ctx->hostSystem,
1151                                esxVI_Occurrence_OptionalItem) < 0) {
1152         goto cleanup;
1153     }
1154 
1155     if (!ctx->hostSystem) {
1156         virReportError(VIR_ERR_INTERNAL_ERROR,
1157                        _("Could not find host system specified in '%s'"), path);
1158         goto cleanup;
1159     }
1160 
1161     result = 0;
1162 
1163  cleanup:
1164     if (root != ctx->service->rootFolder &&
1165         (!ctx->datacenter || root != ctx->datacenter->hostFolder)) {
1166         esxVI_ManagedObjectReference_Free(&root);
1167     }
1168 
1169     esxVI_Folder_Free(&folder);
1170 
1171     return result;
1172 }
1173 
1174 int
esxVI_Context_LookupManagedObjectsByHostSystemIp(esxVI_Context * ctx,const char * hostSystemIPAddress)1175 esxVI_Context_LookupManagedObjectsByHostSystemIp(esxVI_Context *ctx,
1176                                                  const char *hostSystemIPAddress)
1177 {
1178     int result = -1;
1179     esxVI_ManagedObjectReference *managedObjectReference = NULL;
1180 
1181     /* Lookup HostSystem */
1182     if (esxVI_FindByIp(ctx, NULL, hostSystemIPAddress, esxVI_Boolean_False,
1183                        &managedObjectReference) < 0 ||
1184         esxVI_LookupHostSystem(ctx, NULL, managedObjectReference, NULL,
1185                                &ctx->hostSystem,
1186                                esxVI_Occurrence_RequiredItem) < 0) {
1187         goto cleanup;
1188     }
1189 
1190     /* Lookup (Cluster)ComputeResource */
1191     if (esxVI_LookupComputeResource(ctx, NULL, ctx->hostSystem->_reference,
1192                                     NULL, &ctx->computeResource,
1193                                     esxVI_Occurrence_RequiredItem) < 0) {
1194         goto cleanup;
1195     }
1196 
1197     if (!ctx->computeResource->resourcePool) {
1198         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1199                        _("Could not retrieve resource pool"));
1200         goto cleanup;
1201     }
1202 
1203     /* Lookup Datacenter */
1204     if (esxVI_LookupDatacenter(ctx, NULL, ctx->computeResource->_reference,
1205                                NULL, &ctx->datacenter,
1206                                esxVI_Occurrence_RequiredItem) < 0) {
1207         goto cleanup;
1208     }
1209 
1210     result = 0;
1211 
1212  cleanup:
1213     esxVI_ManagedObjectReference_Free(&managedObjectReference);
1214 
1215     return result;
1216 }
1217 
1218 int
esxVI_Context_Execute(esxVI_Context * ctx,const char * methodName,const char * request,esxVI_Response ** response,esxVI_Occurrence occurrence)1219 esxVI_Context_Execute(esxVI_Context *ctx, const char *methodName,
1220                       const char *request, esxVI_Response **response,
1221                       esxVI_Occurrence occurrence)
1222 {
1223     int result = -1;
1224     g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
1225     esxVI_Fault *fault = NULL;
1226     g_autofree char *xpathExpression = NULL;
1227     g_autoptr(xmlXPathContext) xpathContext = NULL;
1228     xmlNodePtr responseNode = NULL;
1229 
1230     if (!request || !response || *response) {
1231         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1232         return -1;
1233     }
1234 
1235     if (esxVI_Response_Alloc(response) < 0)
1236         return -1;
1237 
1238     virMutexLock(&ctx->curl->lock);
1239 
1240     curl_easy_setopt(ctx->curl->handle, CURLOPT_URL, ctx->url);
1241     curl_easy_setopt(ctx->curl->handle, CURLOPT_RANGE, NULL);
1242     curl_easy_setopt(ctx->curl->handle, CURLOPT_WRITEDATA, &buffer);
1243     curl_easy_setopt(ctx->curl->handle, CURLOPT_UPLOAD, 0);
1244     curl_easy_setopt(ctx->curl->handle, CURLOPT_POSTFIELDS, request);
1245     curl_easy_setopt(ctx->curl->handle, CURLOPT_POSTFIELDSIZE, strlen(request));
1246 
1247     (*response)->responseCode = esxVI_CURL_Perform(ctx->curl, ctx->url);
1248 
1249     virMutexUnlock(&ctx->curl->lock);
1250 
1251     if ((*response)->responseCode < 0)
1252         goto cleanup;
1253 
1254     (*response)->content = virBufferContentAndReset(&buffer);
1255 
1256     if ((*response)->responseCode == 500 || (*response)->responseCode == 200) {
1257         (*response)->document = virXMLParseStringCtxt((*response)->content,
1258                                                       _("(esx execute response)"),
1259                                                       &xpathContext);
1260 
1261         if (!(*response)->document)
1262             goto cleanup;
1263 
1264         xmlXPathRegisterNs(xpathContext, BAD_CAST "soapenv",
1265                            BAD_CAST "http://schemas.xmlsoap.org/soap/envelope/");
1266         xmlXPathRegisterNs(xpathContext, BAD_CAST "vim", BAD_CAST "urn:vim25");
1267 
1268         if ((*response)->responseCode == 500) {
1269             (*response)->node =
1270               virXPathNode("/soapenv:Envelope/soapenv:Body/soapenv:Fault",
1271                            xpathContext);
1272 
1273             if (!(*response)->node) {
1274                 virReportError(VIR_ERR_INTERNAL_ERROR,
1275                                _("HTTP response code %d for call to '%s'. "
1276                                  "Fault is unknown, XPath evaluation failed"),
1277                                (*response)->responseCode, methodName);
1278                 goto cleanup;
1279             }
1280 
1281             if (esxVI_Fault_Deserialize((*response)->node, &fault) < 0) {
1282                 virReportError(VIR_ERR_INTERNAL_ERROR,
1283                                _("HTTP response code %d for call to '%s'. "
1284                                  "Fault is unknown, deserialization failed"),
1285                                (*response)->responseCode, methodName);
1286                 goto cleanup;
1287             }
1288 
1289             virReportError(VIR_ERR_INTERNAL_ERROR,
1290                            _("HTTP response code %d for call to '%s'. "
1291                              "Fault: %s - %s"), (*response)->responseCode,
1292                            methodName, fault->faultcode, fault->faultstring);
1293 
1294             /* FIXME: Dump raw response until detail part gets deserialized */
1295             VIR_DEBUG("HTTP response code %d for call to '%s' [[[[%s]]]]",
1296                       (*response)->responseCode, methodName,
1297                       (*response)->content);
1298 
1299             goto cleanup;
1300         } else {
1301             xpathExpression = g_strdup_printf("/soapenv:Envelope/soapenv:Body/vim:%sResponse",
1302                                               methodName);
1303 
1304             responseNode = virXPathNode(xpathExpression, xpathContext);
1305 
1306             if (!responseNode) {
1307                 virReportError(VIR_ERR_INTERNAL_ERROR,
1308                                _("XPath evaluation of response for call to '%s' "
1309                                  "failed"), methodName);
1310                 goto cleanup;
1311             }
1312 
1313             xpathContext->node = responseNode;
1314             (*response)->node = virXPathNode("./vim:returnval", xpathContext);
1315 
1316             switch (occurrence) {
1317               case esxVI_Occurrence_RequiredItem:
1318                 if (!(*response)->node) {
1319                     virReportError(VIR_ERR_INTERNAL_ERROR,
1320                                    _("Call to '%s' returned an empty result, "
1321                                      "expecting a non-empty result"), methodName);
1322                     goto cleanup;
1323                 } else if ((*response)->node->next) {
1324                     virReportError(VIR_ERR_INTERNAL_ERROR,
1325                                    _("Call to '%s' returned a list, expecting "
1326                                      "exactly one item"), methodName);
1327                     goto cleanup;
1328                 }
1329 
1330                 break;
1331 
1332               case esxVI_Occurrence_RequiredList:
1333                 if (!(*response)->node) {
1334                     virReportError(VIR_ERR_INTERNAL_ERROR,
1335                                    _("Call to '%s' returned an empty result, "
1336                                      "expecting a non-empty result"), methodName);
1337                     goto cleanup;
1338                 }
1339 
1340                 break;
1341 
1342               case esxVI_Occurrence_OptionalItem:
1343                 if ((*response)->node &&
1344                     (*response)->node->next) {
1345                     virReportError(VIR_ERR_INTERNAL_ERROR,
1346                                    _("Call to '%s' returned a list, expecting "
1347                                      "exactly one item"), methodName);
1348                     goto cleanup;
1349                 }
1350 
1351                 break;
1352 
1353               case esxVI_Occurrence_OptionalList:
1354                 /* Any amount of items is valid */
1355                 break;
1356 
1357               case esxVI_Occurrence_None:
1358                 if ((*response)->node) {
1359                     virReportError(VIR_ERR_INTERNAL_ERROR,
1360                                    _("Call to '%s' returned something, expecting "
1361                                      "an empty result"), methodName);
1362                     goto cleanup;
1363                 }
1364 
1365                 break;
1366 
1367               case esxVI_Occurrence_Undefined:
1368               default:
1369                 virReportEnumRangeError(esxVI_Occurrence, occurrence);
1370                 goto cleanup;
1371             }
1372         }
1373     } else {
1374         virReportError(VIR_ERR_HTTP_ERROR,
1375                        _("HTTP response code %d for call to '%s'"),
1376                        (*response)->responseCode, methodName);
1377         goto cleanup;
1378     }
1379 
1380     result = 0;
1381 
1382  cleanup:
1383     if (result < 0) {
1384         esxVI_Response_Free(response);
1385         esxVI_Fault_Free(&fault);
1386     }
1387 
1388     return result;
1389 }
1390 
1391 
1392 
1393 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1394  * Response
1395  */
1396 
1397 /* esxVI_Response_Alloc */
1398 ESX_VI__TEMPLATE__ALLOC(Response)
1399 
1400 /* esxVI_Response_Free */
1401 ESX_VI__TEMPLATE__FREE(Response,
1402 {
1403     g_free(item->content);
1404 
1405     xmlFreeDoc(item->document);
1406 })
1407 
1408 
1409 
1410 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1411  * Enumeration
1412  */
1413 
1414 int
esxVI_Enumeration_CastFromAnyType(const esxVI_Enumeration * enumeration,esxVI_AnyType * anyType,int * value)1415 esxVI_Enumeration_CastFromAnyType(const esxVI_Enumeration *enumeration,
1416                                   esxVI_AnyType *anyType, int *value)
1417 {
1418     size_t i;
1419 
1420     if (!anyType || !value) {
1421         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1422         return -1;
1423     }
1424 
1425     *value = 0; /* undefined */
1426 
1427     if (anyType->type != enumeration->type) {
1428         virReportError(VIR_ERR_INTERNAL_ERROR,
1429                        _("Expecting type '%s' but found '%s'"),
1430                        esxVI_Type_ToString(enumeration->type),
1431                        esxVI_AnyType_TypeToString(anyType));
1432         return -1;
1433     }
1434 
1435     for (i = 0; enumeration->values[i].name; ++i) {
1436         if (STREQ(anyType->value, enumeration->values[i].name)) {
1437             *value = enumeration->values[i].value;
1438             return 0;
1439         }
1440     }
1441 
1442     virReportError(VIR_ERR_INTERNAL_ERROR,
1443                    _("Unknown value '%s' for %s"), anyType->value,
1444                    esxVI_Type_ToString(enumeration->type));
1445 
1446     return -1;
1447 }
1448 
1449 int
esxVI_Enumeration_Serialize(const esxVI_Enumeration * enumeration,int value,const char * element,virBuffer * output)1450 esxVI_Enumeration_Serialize(const esxVI_Enumeration *enumeration,
1451                             int value, const char *element, virBuffer *output)
1452 {
1453     size_t i;
1454     const char *name = NULL;
1455 
1456     if (!element || !output) {
1457         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1458         return -1;
1459     }
1460 
1461     if (value == 0) { /* undefined */
1462         return 0;
1463     }
1464 
1465     for (i = 0; enumeration->values[i].name; ++i) {
1466         if (value == enumeration->values[i].value) {
1467             name = enumeration->values[i].name;
1468             break;
1469         }
1470     }
1471 
1472     if (!name) {
1473         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1474         return -1;
1475     }
1476 
1477     ESV_VI__XML_TAG__OPEN(output, element,
1478                           esxVI_Type_ToString(enumeration->type));
1479 
1480     virBufferAdd(output, name, -1);
1481 
1482     ESV_VI__XML_TAG__CLOSE(output, element);
1483 
1484     return 0;
1485 }
1486 
1487 int
esxVI_Enumeration_Deserialize(const esxVI_Enumeration * enumeration,xmlNodePtr node,int * value)1488 esxVI_Enumeration_Deserialize(const esxVI_Enumeration *enumeration,
1489                               xmlNodePtr node, int *value)
1490 {
1491     size_t i;
1492     int result = -1;
1493     g_autofree char *name = NULL;
1494 
1495     if (!value) {
1496         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1497         return -1;
1498     }
1499 
1500     *value = 0; /* undefined */
1501 
1502     if (esxVI_String_DeserializeValue(node, &name) < 0)
1503         return -1;
1504 
1505     for (i = 0; enumeration->values[i].name; ++i) {
1506         if (STREQ(name, enumeration->values[i].name)) {
1507             *value = enumeration->values[i].value;
1508             result = 0;
1509             break;
1510         }
1511     }
1512 
1513     if (result < 0) {
1514         virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown value '%s' for %s"),
1515                        name, esxVI_Type_ToString(enumeration->type));
1516     }
1517 
1518     return result;
1519 }
1520 
1521 
1522 
1523 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1524  * List
1525  */
1526 
1527 int
esxVI_List_Append(esxVI_List ** list,esxVI_List * item)1528 esxVI_List_Append(esxVI_List **list, esxVI_List *item)
1529 {
1530     esxVI_List *next = NULL;
1531 
1532     if (!list || !item) {
1533         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1534         return -1;
1535     }
1536 
1537     if (!(*list)) {
1538         *list = item;
1539         return 0;
1540     }
1541 
1542     next = *list;
1543 
1544     while (next->_next)
1545         next = next->_next;
1546 
1547     next->_next = item;
1548 
1549     return 0;
1550 }
1551 
1552 int
esxVI_List_DeepCopy(esxVI_List ** destList,esxVI_List * srcList,esxVI_List_DeepCopyFunc deepCopyFunc,esxVI_List_FreeFunc freeFunc)1553 esxVI_List_DeepCopy(esxVI_List **destList, esxVI_List *srcList,
1554                     esxVI_List_DeepCopyFunc deepCopyFunc,
1555                     esxVI_List_FreeFunc freeFunc)
1556 {
1557     esxVI_List *dest = NULL;
1558     esxVI_List *src = NULL;
1559 
1560     ESX_VI_CHECK_ARG_LIST(destList);
1561 
1562     for (src = srcList; src; src = src->_next) {
1563         if (deepCopyFunc(&dest, src) < 0 ||
1564             esxVI_List_Append(destList, dest) < 0) {
1565             goto failure;
1566         }
1567 
1568         dest = NULL;
1569     }
1570 
1571     return 0;
1572 
1573  failure:
1574     freeFunc(&dest);
1575     freeFunc(destList);
1576 
1577     return -1;
1578 }
1579 
1580 int
esxVI_List_CastFromAnyType(esxVI_AnyType * anyType,esxVI_List ** list,esxVI_List_CastFromAnyTypeFunc castFromAnyTypeFunc,esxVI_List_FreeFunc freeFunc)1581 esxVI_List_CastFromAnyType(esxVI_AnyType *anyType, esxVI_List **list,
1582                            esxVI_List_CastFromAnyTypeFunc castFromAnyTypeFunc,
1583                            esxVI_List_FreeFunc freeFunc)
1584 {
1585     int result = -1;
1586     xmlNodePtr childNode = NULL;
1587     esxVI_AnyType *childAnyType = NULL;
1588     esxVI_List *item = NULL;
1589 
1590     if (!list || *list || !castFromAnyTypeFunc || !freeFunc) {
1591         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1592         return -1;
1593     }
1594 
1595     if (!anyType)
1596         return 0;
1597 
1598     if (! STRPREFIX(anyType->other, "ArrayOf")) {
1599         virReportError(VIR_ERR_INTERNAL_ERROR,
1600                        _("Expecting type to begin with 'ArrayOf' but found '%s'"),
1601                        anyType->other);
1602         return -1;
1603     }
1604 
1605     for (childNode = anyType->node->children; childNode;
1606          childNode = childNode->next) {
1607         if (childNode->type != XML_ELEMENT_NODE) {
1608             virReportError(VIR_ERR_INTERNAL_ERROR,
1609                            _("Wrong XML element type %d"), childNode->type);
1610             goto cleanup;
1611         }
1612 
1613         esxVI_AnyType_Free(&childAnyType);
1614 
1615         if (esxVI_AnyType_Deserialize(childNode, &childAnyType) < 0 ||
1616             castFromAnyTypeFunc(childAnyType, &item) < 0 ||
1617             esxVI_List_Append(list, item) < 0) {
1618             goto cleanup;
1619         }
1620 
1621         item = NULL;
1622     }
1623 
1624     result = 0;
1625 
1626  cleanup:
1627     if (result < 0) {
1628         freeFunc(&item);
1629         freeFunc(list);
1630     }
1631 
1632     esxVI_AnyType_Free(&childAnyType);
1633 
1634     return result;
1635 }
1636 
1637 int
esxVI_List_Serialize(esxVI_List * list,const char * element,virBuffer * output,esxVI_List_SerializeFunc serializeFunc)1638 esxVI_List_Serialize(esxVI_List *list, const char *element,
1639                      virBuffer *output,
1640                      esxVI_List_SerializeFunc serializeFunc)
1641 {
1642     esxVI_List *item = NULL;
1643 
1644     if (!element || !output || !serializeFunc) {
1645         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1646         return -1;
1647     }
1648 
1649     if (!list)
1650         return 0;
1651 
1652     for (item = list; item; item = item->_next) {
1653         if (serializeFunc(item, element, output) < 0)
1654             return -1;
1655     }
1656 
1657     return 0;
1658 }
1659 
1660 int
esxVI_List_Deserialize(xmlNodePtr node,esxVI_List ** list,esxVI_List_DeserializeFunc deserializeFunc,esxVI_List_FreeFunc freeFunc)1661 esxVI_List_Deserialize(xmlNodePtr node, esxVI_List **list,
1662                        esxVI_List_DeserializeFunc deserializeFunc,
1663                        esxVI_List_FreeFunc freeFunc)
1664 {
1665     esxVI_List *item = NULL;
1666 
1667     if (!list || *list || !deserializeFunc || !freeFunc) {
1668         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1669         return -1;
1670     }
1671 
1672     if (!node)
1673         return 0;
1674 
1675     for (; node; node = node->next) {
1676         if (node->type != XML_ELEMENT_NODE) {
1677             virReportError(VIR_ERR_INTERNAL_ERROR,
1678                            _("Wrong XML element type %d"), node->type);
1679             goto failure;
1680         }
1681 
1682         if (deserializeFunc(node, &item) < 0 ||
1683             esxVI_List_Append(list, item) < 0) {
1684             goto failure;
1685         }
1686 
1687         item = NULL;
1688     }
1689 
1690     return 0;
1691 
1692  failure:
1693     freeFunc(&item);
1694     freeFunc(list);
1695 
1696     return -1;
1697 }
1698 
1699 
1700 
1701 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1702  * Utility and Convenience Functions
1703  *
1704  * Function naming scheme:
1705  *  - 'lookup' functions query the ESX or vCenter for information
1706  *  - 'get' functions get information from a local object
1707  */
1708 
1709 int
esxVI_BuildSelectSet(esxVI_SelectionSpec ** selectSet,const char * name,const char * type,const char * path,const char * selectSetNames)1710 esxVI_BuildSelectSet(esxVI_SelectionSpec **selectSet,
1711                      const char *name, const char *type,
1712                      const char *path, const char *selectSetNames)
1713 {
1714     esxVI_TraversalSpec *traversalSpec = NULL;
1715     esxVI_SelectionSpec *selectionSpec = NULL;
1716     const char *currentSelectSetName = NULL;
1717 
1718     if (!selectSet) {
1719         /*
1720          * Don't check for *selectSet != NULL here because selectSet is a list
1721          * and might contain items already. This function appends to selectSet.
1722          */
1723         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1724         return -1;
1725     }
1726 
1727     if (esxVI_TraversalSpec_Alloc(&traversalSpec) < 0)
1728         goto failure;
1729 
1730     traversalSpec->name = g_strdup(name);
1731     traversalSpec->type = g_strdup(type);
1732     traversalSpec->path = g_strdup(path);
1733     traversalSpec->skip = esxVI_Boolean_False;
1734 
1735     if (selectSetNames) {
1736         currentSelectSetName = selectSetNames;
1737 
1738         while (currentSelectSetName && *currentSelectSetName != '\0') {
1739             if (esxVI_SelectionSpec_Alloc(&selectionSpec) < 0)
1740                 goto failure;
1741 
1742             selectionSpec->name = g_strdup(currentSelectSetName);
1743 
1744             if (esxVI_SelectionSpec_AppendToList(&traversalSpec->selectSet,
1745                                                  selectionSpec) < 0)
1746                 goto failure;
1747 
1748             selectionSpec = NULL;
1749             currentSelectSetName += strlen(currentSelectSetName) + 1;
1750         }
1751     }
1752 
1753     if (esxVI_SelectionSpec_AppendToList(selectSet,
1754                                          esxVI_SelectionSpec_DynamicCast
1755                                            (traversalSpec)) < 0) {
1756         goto failure;
1757     }
1758 
1759     return 0;
1760 
1761  failure:
1762     esxVI_TraversalSpec_Free(&traversalSpec);
1763     esxVI_SelectionSpec_Free(&selectionSpec);
1764 
1765     return -1;
1766 }
1767 
1768 
1769 
1770 int
esxVI_BuildSelectSetCollection(esxVI_Context * ctx)1771 esxVI_BuildSelectSetCollection(esxVI_Context *ctx)
1772 {
1773     /* Folder -> childEntity (ManagedEntity) */
1774     if (esxVI_BuildSelectSet(&ctx->selectSet_folderToChildEntity,
1775                              "folderToChildEntity",
1776                              "Folder", "childEntity", NULL) < 0) {
1777         return -1;
1778     }
1779 
1780     /* ComputeResource -> host (HostSystem) */
1781     if (esxVI_BuildSelectSet(&ctx->selectSet_computeResourceToHost,
1782                              "computeResourceToHost",
1783                              "ComputeResource", "host", NULL) < 0) {
1784         return -1;
1785     }
1786 
1787     /* ComputeResource -> datastore (Datastore) *//*
1788     if (esxVI_BuildSelectSet(&ctx->selectSet_computeResourceToDatastore,
1789                              "computeResourceToDatastore",
1790                              "ComputeResource", "datastore", NULL) < 0) {
1791         return -1;
1792     }*/
1793 
1794     /* ResourcePool -> resourcePool (ResourcePool) *//*
1795     if (esxVI_BuildSelectSet(&ctx->selectSet_resourcePoolToVm,
1796                              "resourcePoolToResourcePool",
1797                              "ResourcePool", "resourcePool",
1798                              "resourcePoolToResourcePool\0"
1799                              "resourcePoolToVm\0") < 0) {
1800         return -1;
1801     }*/
1802 
1803     /* ResourcePool -> vm (VirtualMachine) *//*
1804     if (esxVI_BuildSelectSet(&ctx->selectSet_resourcePoolToVm,
1805                              "resourcePoolToVm",
1806                              "ResourcePool", "vm", NULL) < 0) {
1807         return -1;
1808     }*/
1809 
1810     /* HostSystem -> parent (ComputeResource) */
1811     if (esxVI_BuildSelectSet(&ctx->selectSet_hostSystemToParent,
1812                              "hostSystemToParent",
1813                              "HostSystem", "parent", NULL) < 0) {
1814         return -1;
1815     }
1816 
1817     /* HostSystem -> vm (VirtualMachine) */
1818     if (esxVI_BuildSelectSet(&ctx->selectSet_hostSystemToVm,
1819                              "hostSystemToVm",
1820                              "HostSystem", "vm", NULL) < 0) {
1821         return -1;
1822     }
1823 
1824     /* HostSystem -> datastore (Datastore) */
1825     if (esxVI_BuildSelectSet(&ctx->selectSet_hostSystemToDatastore,
1826                              "hostSystemToDatastore",
1827                              "HostSystem", "datastore", NULL) < 0) {
1828         return -1;
1829     }
1830 
1831     /* Folder -> parent (Folder, Datacenter) */
1832     if (esxVI_BuildSelectSet(&ctx->selectSet_computeResourceToParentToParent,
1833                              "managedEntityToParent",
1834                              "ManagedEntity", "parent", NULL) < 0) {
1835         return -1;
1836     }
1837 
1838     /* ComputeResource -> parent (Folder) */
1839     if (esxVI_BuildSelectSet(&ctx->selectSet_computeResourceToParentToParent,
1840                              "computeResourceToParent",
1841                              "ComputeResource", "parent",
1842                              "managedEntityToParent\0") < 0) {
1843         return -1;
1844     }
1845 
1846     /* Datacenter -> network (Network) */
1847     if (esxVI_BuildSelectSet(&ctx->selectSet_datacenterToNetwork,
1848                              "datacenterToNetwork",
1849                              "Datacenter", "network", NULL) < 0) {
1850         return -1;
1851     }
1852 
1853     return 0;
1854 }
1855 
1856 
1857 
1858 /*
1859  * Cannot use the SessionIsActive() function here, because at least
1860  * ESX Server 3.5.0 build-64607 and ESX 4.0.0 build-171294 return an
1861  * method-not-implemented fault when calling it. The vCenter Server
1862  * implements this method, but because it can be used to check any
1863  * session it requires the Sessions.ValidateSession privilege that is
1864  * considered as an admin privilege.
1865  *
1866  * Instead query the session manager for the current session of this
1867  * connection and re-login if there is no current session.
1868  */
1869 int
esxVI_EnsureSession(esxVI_Context * ctx)1870 esxVI_EnsureSession(esxVI_Context *ctx)
1871 {
1872     int result = -1;
1873     esxVI_String *propertyNameList = NULL;
1874     esxVI_ObjectContent *sessionManager = NULL;
1875     esxVI_DynamicProperty *dynamicProperty = NULL;
1876     esxVI_UserSession *currentSession = NULL;
1877     g_autofree char *escapedPassword = NULL;
1878 
1879     if (!ctx->sessionLock) {
1880         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid call, no mutex"));
1881         return -1;
1882     }
1883 
1884     virMutexLock(ctx->sessionLock);
1885 
1886     if (!ctx->session) {
1887         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid call, no session"));
1888         goto cleanup;
1889     }
1890 
1891     escapedPassword = esxUtil_EscapeForXml(ctx->password);
1892 
1893     if (!escapedPassword) {
1894         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1895                        _("Failed to escape password for XML"));
1896         goto cleanup;
1897     }
1898 
1899     if (esxVI_String_AppendValueToList(&propertyNameList,
1900                                        "currentSession") < 0 ||
1901         esxVI_LookupObjectContentByType(ctx, ctx->service->sessionManager,
1902                                         "SessionManager", propertyNameList,
1903                                         &sessionManager,
1904                                         esxVI_Occurrence_RequiredItem) < 0) {
1905         goto cleanup;
1906     }
1907 
1908     for (dynamicProperty = sessionManager->propSet; dynamicProperty;
1909          dynamicProperty = dynamicProperty->_next) {
1910         if (STREQ(dynamicProperty->name, "currentSession")) {
1911             if (esxVI_UserSession_CastFromAnyType(dynamicProperty->val,
1912                                                   &currentSession) < 0) {
1913                 goto cleanup;
1914             }
1915 
1916             break;
1917         } else {
1918             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
1919         }
1920     }
1921 
1922     if (!currentSession) {
1923         esxVI_UserSession_Free(&ctx->session);
1924 
1925         if (esxVI_Login(ctx, ctx->username, escapedPassword, NULL,
1926                         &ctx->session) < 0) {
1927             goto cleanup;
1928         }
1929     } else if (STRNEQ(ctx->session->key, currentSession->key)) {
1930         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1931                        _("Key of the current session differs from the key at "
1932                          "last login"));
1933         goto cleanup;
1934     }
1935 
1936     result = 0;
1937 
1938  cleanup:
1939     virMutexUnlock(ctx->sessionLock);
1940 
1941     esxVI_String_Free(&propertyNameList);
1942     esxVI_ObjectContent_Free(&sessionManager);
1943     esxVI_UserSession_Free(&currentSession);
1944 
1945     return result;
1946 }
1947 
1948 
1949 
1950 int
esxVI_LookupObjectContentByType(esxVI_Context * ctx,esxVI_ManagedObjectReference * root,const char * type,esxVI_String * propertyNameList,esxVI_ObjectContent ** objectContentList,esxVI_Occurrence occurrence)1951 esxVI_LookupObjectContentByType(esxVI_Context *ctx,
1952                                 esxVI_ManagedObjectReference *root,
1953                                 const char *type,
1954                                 esxVI_String *propertyNameList,
1955                                 esxVI_ObjectContent **objectContentList,
1956                                 esxVI_Occurrence occurrence)
1957 {
1958     int result = -1;
1959     esxVI_ObjectSpec *objectSpec = NULL;
1960     bool objectSpec_isAppended = false;
1961     esxVI_PropertySpec *propertySpec = NULL;
1962     bool propertySpec_isAppended = false;
1963     esxVI_PropertyFilterSpec *propertyFilterSpec = NULL;
1964 
1965     ESX_VI_CHECK_ARG_LIST(objectContentList);
1966 
1967     if (esxVI_ObjectSpec_Alloc(&objectSpec) < 0)
1968         return -1;
1969 
1970     objectSpec->obj = root;
1971     objectSpec->skip = esxVI_Boolean_False;
1972 
1973     if (STRNEQ(root->type, type) || STREQ(root->type, "Folder")) {
1974         if (STREQ(root->type, "Folder")) {
1975             if (STREQ(type, "Folder") || STREQ(type, "Datacenter") ||
1976                 STREQ(type, "ComputeResource") ||
1977                 STREQ(type, "ClusterComputeResource")) {
1978                 objectSpec->selectSet = ctx->selectSet_folderToChildEntity;
1979             } else {
1980                 virReportError(VIR_ERR_INTERNAL_ERROR,
1981                                _("Invalid lookup of '%s' from '%s'"),
1982                                type, root->type);
1983                 goto cleanup;
1984             }
1985         } else if (STREQ(root->type, "ComputeResource") ||
1986                    STREQ(root->type, "ClusterComputeResource")) {
1987             if (STREQ(type, "HostSystem")) {
1988                 objectSpec->selectSet = ctx->selectSet_computeResourceToHost;
1989             } else if (STREQ(type, "Datacenter")) {
1990                 objectSpec->selectSet = ctx->selectSet_computeResourceToParentToParent;
1991             } else {
1992                 virReportError(VIR_ERR_INTERNAL_ERROR,
1993                                _("Invalid lookup of '%s' from '%s'"),
1994                                type, root->type);
1995                 goto cleanup;
1996             }
1997         } else if (STREQ(root->type, "HostSystem")) {
1998             if (STREQ(type, "ComputeResource") ||
1999                 STREQ(type, "ClusterComputeResource")) {
2000                 objectSpec->selectSet = ctx->selectSet_hostSystemToParent;
2001             } else if (STREQ(type, "VirtualMachine")) {
2002                 objectSpec->selectSet = ctx->selectSet_hostSystemToVm;
2003             } else if (STREQ(type, "Datastore")) {
2004                 objectSpec->selectSet = ctx->selectSet_hostSystemToDatastore;
2005             } else {
2006                 virReportError(VIR_ERR_INTERNAL_ERROR,
2007                                _("Invalid lookup of '%s' from '%s'"),
2008                                type, root->type);
2009                 goto cleanup;
2010             }
2011         } else if (STREQ(root->type, "Datacenter")) {
2012             if (STREQ(type, "Network")) {
2013                 objectSpec->selectSet = ctx->selectSet_datacenterToNetwork;
2014             } else {
2015                 virReportError(VIR_ERR_INTERNAL_ERROR,
2016                                _("Invalid lookup of '%s' from '%s'"),
2017                                type, root->type);
2018                 goto cleanup;
2019             }
2020         } else {
2021             virReportError(VIR_ERR_INTERNAL_ERROR,
2022                            _("Invalid lookup from '%s'"), root->type);
2023             goto cleanup;
2024         }
2025     }
2026 
2027     if (esxVI_PropertySpec_Alloc(&propertySpec) < 0)
2028         goto cleanup;
2029 
2030     propertySpec->type = (char *)type;
2031     propertySpec->pathSet = propertyNameList;
2032 
2033     if (esxVI_PropertyFilterSpec_Alloc(&propertyFilterSpec) < 0 ||
2034         esxVI_PropertySpec_AppendToList(&propertyFilterSpec->propSet,
2035                                         propertySpec) < 0) {
2036         goto cleanup;
2037     }
2038 
2039     propertySpec_isAppended = true;
2040 
2041     if (esxVI_ObjectSpec_AppendToList(&propertyFilterSpec->objectSet,
2042                                       objectSpec) < 0) {
2043         goto cleanup;
2044     }
2045 
2046     objectSpec_isAppended = true;
2047 
2048     if (esxVI_RetrieveProperties(ctx, propertyFilterSpec,
2049                                  objectContentList) < 0) {
2050         goto cleanup;
2051     }
2052 
2053     if (!(*objectContentList)) {
2054         switch (occurrence) {
2055           case esxVI_Occurrence_OptionalItem:
2056           case esxVI_Occurrence_OptionalList:
2057             result = 0;
2058             break;
2059 
2060           case esxVI_Occurrence_RequiredItem:
2061             virReportError(VIR_ERR_INTERNAL_ERROR,
2062                            _("Could not lookup '%s' from '%s'"),
2063                            type, root->type);
2064             break;
2065 
2066           case esxVI_Occurrence_RequiredList:
2067             virReportError(VIR_ERR_INTERNAL_ERROR,
2068                            _("Could not lookup '%s' list from '%s'"),
2069                            type, root->type);
2070             break;
2071 
2072           case esxVI_Occurrence_None:
2073           case esxVI_Occurrence_Undefined:
2074           default:
2075             virReportEnumRangeError(esxVI_Occurrence, occurrence);
2076             break;
2077         }
2078 
2079         goto cleanup;
2080     }
2081 
2082     result = 0;
2083 
2084  cleanup:
2085     /*
2086      * Remove values given by the caller from the data structures to prevent
2087      * them from being freed by the call to esxVI_PropertyFilterSpec_Free().
2088      * objectSpec cannot be NULL here.
2089      */
2090     objectSpec->obj = NULL;
2091     objectSpec->selectSet = NULL;
2092 
2093     if (propertySpec) {
2094         propertySpec->type = NULL;
2095         propertySpec->pathSet = NULL;
2096     }
2097 
2098     if (!objectSpec_isAppended)
2099         esxVI_ObjectSpec_Free(&objectSpec);
2100 
2101     if (!propertySpec_isAppended)
2102         esxVI_PropertySpec_Free(&propertySpec);
2103 
2104     esxVI_PropertyFilterSpec_Free(&propertyFilterSpec);
2105 
2106     return result;
2107 }
2108 
2109 
2110 
2111 int
esxVI_GetManagedEntityStatus(esxVI_ObjectContent * objectContent,const char * propertyName,esxVI_ManagedEntityStatus * managedEntityStatus)2112 esxVI_GetManagedEntityStatus(esxVI_ObjectContent *objectContent,
2113                              const char *propertyName,
2114                              esxVI_ManagedEntityStatus *managedEntityStatus)
2115 {
2116     esxVI_DynamicProperty *dynamicProperty;
2117 
2118     for (dynamicProperty = objectContent->propSet; dynamicProperty;
2119          dynamicProperty = dynamicProperty->_next) {
2120         if (STREQ(dynamicProperty->name, propertyName)) {
2121             return esxVI_ManagedEntityStatus_CastFromAnyType
2122                      (dynamicProperty->val, managedEntityStatus);
2123         }
2124     }
2125 
2126     virReportError(VIR_ERR_INTERNAL_ERROR,
2127                    _("Missing '%s' property while looking for "
2128                      "ManagedEntityStatus"), propertyName);
2129 
2130     return -1;
2131 }
2132 
2133 
2134 
2135 int
esxVI_GetVirtualMachinePowerState(esxVI_ObjectContent * virtualMachine,esxVI_VirtualMachinePowerState * powerState)2136 esxVI_GetVirtualMachinePowerState(esxVI_ObjectContent *virtualMachine,
2137                                   esxVI_VirtualMachinePowerState *powerState)
2138 {
2139     esxVI_DynamicProperty *dynamicProperty;
2140 
2141     for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
2142          dynamicProperty = dynamicProperty->_next) {
2143         if (STREQ(dynamicProperty->name, "runtime.powerState")) {
2144             return esxVI_VirtualMachinePowerState_CastFromAnyType
2145                      (dynamicProperty->val, powerState);
2146         }
2147     }
2148 
2149     virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2150                    _("Missing 'runtime.powerState' property"));
2151 
2152     return -1;
2153 }
2154 
2155 
2156 
2157 int
esxVI_GetVirtualMachineQuestionInfo(esxVI_ObjectContent * virtualMachine,esxVI_VirtualMachineQuestionInfo ** questionInfo)2158 esxVI_GetVirtualMachineQuestionInfo
2159   (esxVI_ObjectContent *virtualMachine,
2160    esxVI_VirtualMachineQuestionInfo **questionInfo)
2161 {
2162     esxVI_DynamicProperty *dynamicProperty;
2163 
2164     ESX_VI_CHECK_ARG_LIST(questionInfo);
2165 
2166     for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
2167          dynamicProperty = dynamicProperty->_next) {
2168         if (STREQ(dynamicProperty->name, "runtime.question")) {
2169             if (esxVI_VirtualMachineQuestionInfo_CastFromAnyType
2170                   (dynamicProperty->val, questionInfo) < 0) {
2171                 return -1;
2172             }
2173         }
2174     }
2175 
2176     return 0;
2177 }
2178 
2179 
2180 int
esxVI_GetVirtualMachineMORef(esxVI_ObjectContent * virtualMachine,char ** moref)2181 esxVI_GetVirtualMachineMORef(esxVI_ObjectContent *virtualMachine,
2182                              char **moref)
2183 {
2184     for (; virtualMachine != NULL; virtualMachine = virtualMachine->_next) {
2185         if (virtualMachine->obj &&
2186             STREQ(virtualMachine->obj->type, "VirtualMachine") &&
2187             virtualMachine->obj->value) {
2188             *moref = g_strdup(virtualMachine->obj->value);
2189             return 0;
2190         }
2191     }
2192     return -1;
2193 }
2194 
2195 int
esxVI_GetBoolean(esxVI_ObjectContent * objectContent,const char * propertyName,esxVI_Boolean * value,esxVI_Occurrence occurrence)2196 esxVI_GetBoolean(esxVI_ObjectContent *objectContent, const char *propertyName,
2197                  esxVI_Boolean *value, esxVI_Occurrence occurrence)
2198 {
2199     esxVI_DynamicProperty *dynamicProperty;
2200 
2201     if (!value || *value != esxVI_Boolean_Undefined) {
2202         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2203         return -1;
2204     }
2205 
2206     for (dynamicProperty = objectContent->propSet; dynamicProperty;
2207          dynamicProperty = dynamicProperty->_next) {
2208         if (STREQ(dynamicProperty->name, propertyName)) {
2209             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2210                                          esxVI_Type_Boolean) < 0) {
2211                 return -1;
2212             }
2213 
2214             *value = dynamicProperty->val->boolean;
2215             break;
2216         }
2217     }
2218 
2219     if (*value == esxVI_Boolean_Undefined &&
2220         occurrence == esxVI_Occurrence_RequiredItem) {
2221         virReportError(VIR_ERR_INTERNAL_ERROR,
2222                        _("Missing '%s' property"), propertyName);
2223         return -1;
2224     }
2225 
2226     return 0;
2227 }
2228 
2229 
2230 
2231 int
esxVI_GetInt(esxVI_ObjectContent * objectContent,const char * propertyName,esxVI_Int ** value,esxVI_Occurrence occurrence)2232 esxVI_GetInt(esxVI_ObjectContent *objectContent, const char *propertyName,
2233              esxVI_Int **value, esxVI_Occurrence occurrence)
2234 {
2235     esxVI_DynamicProperty *dynamicProperty;
2236 
2237     ESX_VI_CHECK_ARG_LIST(value);
2238 
2239     for (dynamicProperty = objectContent->propSet; dynamicProperty;
2240          dynamicProperty = dynamicProperty->_next) {
2241         if (STREQ(dynamicProperty->name, propertyName)) {
2242             if (esxVI_Int_CastFromAnyType(dynamicProperty->val, value) < 0)
2243                 return -1;
2244 
2245             break;
2246         }
2247     }
2248 
2249     if (!(*value) && occurrence == esxVI_Occurrence_RequiredItem) {
2250         virReportError(VIR_ERR_INTERNAL_ERROR,
2251                        _("Missing '%s' property"), propertyName);
2252         return -1;
2253     }
2254 
2255     return 0;
2256 }
2257 
2258 
2259 
2260 int
esxVI_GetLong(esxVI_ObjectContent * objectContent,const char * propertyName,esxVI_Long ** value,esxVI_Occurrence occurrence)2261 esxVI_GetLong(esxVI_ObjectContent *objectContent, const char *propertyName,
2262               esxVI_Long **value, esxVI_Occurrence occurrence)
2263 {
2264     esxVI_DynamicProperty *dynamicProperty;
2265 
2266     ESX_VI_CHECK_ARG_LIST(value);
2267 
2268     for (dynamicProperty = objectContent->propSet; dynamicProperty;
2269          dynamicProperty = dynamicProperty->_next) {
2270         if (STREQ(dynamicProperty->name, propertyName)) {
2271             if (esxVI_Long_CastFromAnyType(dynamicProperty->val, value) < 0)
2272                 return -1;
2273 
2274             break;
2275         }
2276     }
2277 
2278     if (!(*value) && occurrence == esxVI_Occurrence_RequiredItem) {
2279         virReportError(VIR_ERR_INTERNAL_ERROR,
2280                        _("Missing '%s' property"), propertyName);
2281         return -1;
2282     }
2283 
2284     return 0;
2285 }
2286 
2287 
2288 
2289 int
esxVI_GetStringValue(esxVI_ObjectContent * objectContent,const char * propertyName,char ** value,esxVI_Occurrence occurrence)2290 esxVI_GetStringValue(esxVI_ObjectContent *objectContent,
2291                      const char *propertyName,
2292                      char **value, esxVI_Occurrence occurrence)
2293 {
2294     esxVI_DynamicProperty *dynamicProperty;
2295 
2296     ESX_VI_CHECK_ARG_LIST(value);
2297 
2298     for (dynamicProperty = objectContent->propSet; dynamicProperty;
2299          dynamicProperty = dynamicProperty->_next) {
2300         if (STREQ(dynamicProperty->name, propertyName)) {
2301             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2302                                          esxVI_Type_String) < 0) {
2303                 return -1;
2304             }
2305 
2306             *value = dynamicProperty->val->string;
2307             break;
2308         }
2309     }
2310 
2311     if (!(*value) && occurrence == esxVI_Occurrence_RequiredItem) {
2312         virReportError(VIR_ERR_INTERNAL_ERROR,
2313                        _("Missing '%s' property"), propertyName);
2314         return -1;
2315     }
2316 
2317     return 0;
2318 }
2319 
2320 
2321 
2322 int
esxVI_GetManagedObjectReference(esxVI_ObjectContent * objectContent,const char * propertyName,esxVI_ManagedObjectReference ** value,esxVI_Occurrence occurrence)2323 esxVI_GetManagedObjectReference(esxVI_ObjectContent *objectContent,
2324                                 const char *propertyName,
2325                                 esxVI_ManagedObjectReference **value,
2326                                 esxVI_Occurrence occurrence)
2327 {
2328     esxVI_DynamicProperty *dynamicProperty;
2329 
2330     ESX_VI_CHECK_ARG_LIST(value);
2331 
2332     for (dynamicProperty = objectContent->propSet; dynamicProperty;
2333          dynamicProperty = dynamicProperty->_next) {
2334         if (STREQ(dynamicProperty->name, propertyName)) {
2335             if (esxVI_ManagedObjectReference_CastFromAnyType
2336                   (dynamicProperty->val, value) < 0) {
2337                 return -1;
2338             }
2339 
2340             break;
2341         }
2342     }
2343 
2344     if (!(*value) && occurrence == esxVI_Occurrence_RequiredItem) {
2345         virReportError(VIR_ERR_INTERNAL_ERROR,
2346                        _("Missing '%s' property"), propertyName);
2347         return -1;
2348     }
2349 
2350     return 0;
2351 }
2352 
2353 
2354 
2355 int
esxVI_LookupNumberOfDomainsByPowerState(esxVI_Context * ctx,esxVI_VirtualMachinePowerState powerState,bool inverse)2356 esxVI_LookupNumberOfDomainsByPowerState(esxVI_Context *ctx,
2357                                         esxVI_VirtualMachinePowerState powerState,
2358                                         bool inverse)
2359 {
2360     bool success = false;
2361     esxVI_String *propertyNameList = NULL;
2362     esxVI_ObjectContent *virtualMachineList = NULL;
2363     esxVI_ObjectContent *virtualMachine = NULL;
2364     esxVI_DynamicProperty *dynamicProperty = NULL;
2365     esxVI_VirtualMachinePowerState powerState_;
2366     int count = 0;
2367 
2368     if (esxVI_String_AppendValueToList(&propertyNameList,
2369                                        "runtime.powerState") < 0 ||
2370         esxVI_LookupVirtualMachineList(ctx, propertyNameList,
2371                                        &virtualMachineList) < 0) {
2372         goto cleanup;
2373     }
2374 
2375     for (virtualMachine = virtualMachineList; virtualMachine;
2376          virtualMachine = virtualMachine->_next) {
2377         for (dynamicProperty = virtualMachine->propSet;
2378              dynamicProperty;
2379              dynamicProperty = dynamicProperty->_next) {
2380             if (STREQ(dynamicProperty->name, "runtime.powerState")) {
2381                 if (esxVI_VirtualMachinePowerState_CastFromAnyType
2382                       (dynamicProperty->val, &powerState_) < 0) {
2383                     goto cleanup;
2384                 }
2385 
2386                 if ((!inverse && powerState_ == powerState) ||
2387                     (inverse && powerState_ != powerState)) {
2388                     count++;
2389                 }
2390             } else {
2391                 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
2392             }
2393         }
2394     }
2395 
2396     success = true;
2397 
2398  cleanup:
2399     esxVI_String_Free(&propertyNameList);
2400     esxVI_ObjectContent_Free(&virtualMachineList);
2401 
2402     return success ? count : -1;
2403 }
2404 
2405 
2406 
2407 int
esxVI_GetVirtualMachineIdentity(esxVI_ObjectContent * virtualMachine,int * id,char ** name,unsigned char * uuid)2408 esxVI_GetVirtualMachineIdentity(esxVI_ObjectContent *virtualMachine,
2409                                 int *id, char **name, unsigned char *uuid)
2410 {
2411     const char *uuid_string = NULL;
2412     esxVI_DynamicProperty *dynamicProperty = NULL;
2413     esxVI_ManagedEntityStatus configStatus = esxVI_ManagedEntityStatus_Undefined;
2414 
2415     if (STRNEQ(virtualMachine->obj->type, "VirtualMachine")) {
2416         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2417                        _("ObjectContent does not reference a virtual machine"));
2418         return -1;
2419     }
2420 
2421     if (id) {
2422         if (esxUtil_ParseVirtualMachineIDString
2423               (virtualMachine->obj->value, id) < 0 || *id <= 0) {
2424             virReportError(VIR_ERR_INTERNAL_ERROR,
2425                            _("Could not parse positive integer from '%s'"),
2426                            virtualMachine->obj->value);
2427             goto failure;
2428         }
2429     }
2430 
2431     if (name) {
2432         if (*name) {
2433             virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2434             goto failure;
2435         }
2436 
2437         for (dynamicProperty = virtualMachine->propSet;
2438              dynamicProperty;
2439              dynamicProperty = dynamicProperty->_next) {
2440             if (STREQ(dynamicProperty->name, "name")) {
2441                 if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2442                                              esxVI_Type_String) < 0) {
2443                     goto failure;
2444                 }
2445 
2446                 *name = g_strdup(dynamicProperty->val->string);
2447 
2448                 if (virVMXUnescapeHexPercent(*name) < 0) {
2449                     virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2450                                    _("Domain name contains invalid escape sequence"));
2451                     goto failure;
2452                 }
2453 
2454                 break;
2455             }
2456         }
2457 
2458         if (!(*name)) {
2459             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2460                            _("Could not get name of virtual machine"));
2461             goto failure;
2462         }
2463     }
2464 
2465     if (uuid) {
2466         if (esxVI_GetManagedEntityStatus(virtualMachine, "configStatus",
2467                                          &configStatus) < 0) {
2468             goto failure;
2469         }
2470 
2471         if (configStatus == esxVI_ManagedEntityStatus_Green) {
2472             for (dynamicProperty = virtualMachine->propSet;
2473                  dynamicProperty;
2474                  dynamicProperty = dynamicProperty->_next) {
2475                 if (STREQ(dynamicProperty->name, "config.uuid")) {
2476                     if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2477                                                  esxVI_Type_String) < 0) {
2478                         goto failure;
2479                     }
2480 
2481                     uuid_string = dynamicProperty->val->string;
2482                     break;
2483                 }
2484             }
2485 
2486             if (!uuid_string) {
2487                 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2488                                _("Could not get UUID of virtual machine"));
2489                 goto failure;
2490             }
2491 
2492             if (virUUIDParse(uuid_string, uuid) < 0) {
2493                 virReportError(VIR_ERR_INTERNAL_ERROR,
2494                                _("Could not parse UUID from string '%s'"),
2495                                uuid_string);
2496                 goto failure;
2497             }
2498         } else {
2499             memset(uuid, 0, VIR_UUID_BUFLEN);
2500 
2501             VIR_WARN("Cannot access UUID, because 'configStatus' property "
2502                       "indicates a config problem");
2503         }
2504     }
2505 
2506     return 0;
2507 
2508  failure:
2509     if (name)
2510         g_clear_pointer(name, g_free);
2511 
2512     return -1;
2513 }
2514 
2515 
2516 
2517 int
esxVI_GetNumberOfSnapshotTrees(esxVI_VirtualMachineSnapshotTree * snapshotTreeList,bool recurse,bool leaves)2518 esxVI_GetNumberOfSnapshotTrees
2519   (esxVI_VirtualMachineSnapshotTree *snapshotTreeList, bool recurse,
2520    bool leaves)
2521 {
2522     int count = 0;
2523     esxVI_VirtualMachineSnapshotTree *snapshotTree;
2524 
2525     for (snapshotTree = snapshotTreeList; snapshotTree;
2526          snapshotTree = snapshotTree->_next) {
2527         if (!(leaves && snapshotTree->childSnapshotList))
2528             count++;
2529         if (recurse)
2530             count += esxVI_GetNumberOfSnapshotTrees
2531                 (snapshotTree->childSnapshotList, true, leaves);
2532     }
2533 
2534     return count;
2535 }
2536 
2537 
2538 
2539 int
esxVI_GetSnapshotTreeNames(esxVI_VirtualMachineSnapshotTree * snapshotTreeList,char ** names,int nameslen,bool recurse,bool leaves)2540 esxVI_GetSnapshotTreeNames(esxVI_VirtualMachineSnapshotTree *snapshotTreeList,
2541                            char **names, int nameslen, bool recurse,
2542                            bool leaves)
2543 {
2544     int count = 0;
2545     int result;
2546     size_t i;
2547     esxVI_VirtualMachineSnapshotTree *snapshotTree;
2548 
2549     for (snapshotTree = snapshotTreeList;
2550          snapshotTree && count < nameslen;
2551          snapshotTree = snapshotTree->_next) {
2552         if (!(leaves && snapshotTree->childSnapshotList)) {
2553             names[count] = g_strdup(snapshotTree->name);
2554 
2555             count++;
2556         }
2557 
2558         if (count >= nameslen)
2559             break;
2560 
2561         if (recurse) {
2562             result = esxVI_GetSnapshotTreeNames(snapshotTree->childSnapshotList,
2563                                                 names + count,
2564                                                 nameslen - count,
2565                                                 true, leaves);
2566 
2567             if (result < 0)
2568                 goto failure;
2569 
2570             count += result;
2571         }
2572     }
2573 
2574     return count;
2575 
2576  failure:
2577     for (i = 0; i < count; ++i)
2578         VIR_FREE(names[i]);
2579 
2580     return -1;
2581 }
2582 
2583 
2584 
2585 int
esxVI_GetSnapshotTreeByName(esxVI_VirtualMachineSnapshotTree * snapshotTreeList,const char * name,esxVI_VirtualMachineSnapshotTree ** snapshotTree,esxVI_VirtualMachineSnapshotTree ** snapshotTreeParent,esxVI_Occurrence occurrence)2586 esxVI_GetSnapshotTreeByName
2587   (esxVI_VirtualMachineSnapshotTree *snapshotTreeList, const char *name,
2588    esxVI_VirtualMachineSnapshotTree **snapshotTree,
2589    esxVI_VirtualMachineSnapshotTree **snapshotTreeParent,
2590    esxVI_Occurrence occurrence)
2591 {
2592     esxVI_VirtualMachineSnapshotTree *candidate;
2593 
2594     if (!snapshotTree || *snapshotTree ||
2595         (snapshotTreeParent && *snapshotTreeParent)) {
2596         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2597         return -1;
2598     }
2599 
2600     for (candidate = snapshotTreeList; candidate;
2601          candidate = candidate->_next) {
2602         if (STREQ(candidate->name, name)) {
2603             *snapshotTree = candidate;
2604             if (snapshotTreeParent)
2605                 *snapshotTreeParent = NULL;
2606             return 1;
2607         }
2608 
2609         if (esxVI_GetSnapshotTreeByName(candidate->childSnapshotList, name,
2610                                         snapshotTree, snapshotTreeParent,
2611                                         occurrence) > 0) {
2612             if (snapshotTreeParent && !(*snapshotTreeParent))
2613                 *snapshotTreeParent = candidate;
2614 
2615             return 1;
2616         }
2617     }
2618 
2619     if (occurrence == esxVI_Occurrence_OptionalItem) {
2620         return 0;
2621     } else {
2622         virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
2623                        _("Could not find snapshot with name '%s'"), name);
2624 
2625         return -1;
2626     }
2627 }
2628 
2629 
2630 
2631 int
esxVI_GetSnapshotTreeBySnapshot(esxVI_VirtualMachineSnapshotTree * snapshotTreeList,esxVI_ManagedObjectReference * snapshot,esxVI_VirtualMachineSnapshotTree ** snapshotTree)2632 esxVI_GetSnapshotTreeBySnapshot
2633   (esxVI_VirtualMachineSnapshotTree *snapshotTreeList,
2634    esxVI_ManagedObjectReference *snapshot,
2635    esxVI_VirtualMachineSnapshotTree **snapshotTree)
2636 {
2637     esxVI_VirtualMachineSnapshotTree *candidate;
2638 
2639     ESX_VI_CHECK_ARG_LIST(snapshotTree);
2640 
2641     for (candidate = snapshotTreeList; candidate;
2642          candidate = candidate->_next) {
2643         if (STREQ(candidate->snapshot->value, snapshot->value)) {
2644             *snapshotTree = candidate;
2645             return 0;
2646         }
2647 
2648         if (esxVI_GetSnapshotTreeBySnapshot(candidate->childSnapshotList,
2649                                             snapshot, snapshotTree) >= 0) {
2650             return 0;
2651         }
2652     }
2653 
2654     virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
2655                    _("Could not find domain snapshot with internal name '%s'"),
2656                    snapshot->value);
2657 
2658     return -1;
2659 }
2660 
2661 
2662 
2663 int
esxVI_LookupHostSystemProperties(esxVI_Context * ctx,esxVI_String * propertyNameList,esxVI_ObjectContent ** hostSystem)2664 esxVI_LookupHostSystemProperties(esxVI_Context *ctx,
2665                                  esxVI_String *propertyNameList,
2666                                  esxVI_ObjectContent **hostSystem)
2667 {
2668     return esxVI_LookupObjectContentByType(ctx, ctx->hostSystem->_reference,
2669                                            "HostSystem", propertyNameList,
2670                                            hostSystem,
2671                                            esxVI_Occurrence_RequiredItem);
2672 }
2673 
2674 
2675 
2676 int
esxVI_LookupVirtualMachineList(esxVI_Context * ctx,esxVI_String * propertyNameList,esxVI_ObjectContent ** virtualMachineList)2677 esxVI_LookupVirtualMachineList(esxVI_Context *ctx,
2678                                esxVI_String *propertyNameList,
2679                                esxVI_ObjectContent **virtualMachineList)
2680 {
2681     /* FIXME: Switch from ctx->hostSystem to ctx->computeResource->resourcePool
2682      *        for cluster support */
2683     return esxVI_LookupObjectContentByType(ctx, ctx->hostSystem->_reference,
2684                                            "VirtualMachine", propertyNameList,
2685                                            virtualMachineList,
2686                                            esxVI_Occurrence_OptionalList);
2687 }
2688 
2689 
2690 
2691 int
esxVI_LookupVirtualMachineByUuid(esxVI_Context * ctx,const unsigned char * uuid,esxVI_String * propertyNameList,esxVI_ObjectContent ** virtualMachine,esxVI_Occurrence occurrence)2692 esxVI_LookupVirtualMachineByUuid(esxVI_Context *ctx, const unsigned char *uuid,
2693                                  esxVI_String *propertyNameList,
2694                                  esxVI_ObjectContent **virtualMachine,
2695                                  esxVI_Occurrence occurrence)
2696 {
2697     int result = -1;
2698     esxVI_ManagedObjectReference *managedObjectReference = NULL;
2699     char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
2700 
2701     ESX_VI_CHECK_ARG_LIST(virtualMachine);
2702 
2703     virUUIDFormat(uuid, uuid_string);
2704 
2705     if (esxVI_FindByUuid(ctx, ctx->datacenter->_reference, uuid_string,
2706                          esxVI_Boolean_True, esxVI_Boolean_Undefined,
2707                          &managedObjectReference) < 0) {
2708         return -1;
2709     }
2710 
2711     if (!managedObjectReference) {
2712         if (occurrence == esxVI_Occurrence_OptionalItem) {
2713             result = 0;
2714 
2715             goto cleanup;
2716         } else {
2717             virReportError(VIR_ERR_NO_DOMAIN,
2718                            _("Could not find domain with UUID '%s'"),
2719                            uuid_string);
2720             goto cleanup;
2721         }
2722     }
2723 
2724     if (esxVI_LookupObjectContentByType(ctx, managedObjectReference,
2725                                         "VirtualMachine", propertyNameList,
2726                                         virtualMachine,
2727                                         esxVI_Occurrence_RequiredItem) < 0) {
2728         goto cleanup;
2729     }
2730 
2731     result = 0;
2732 
2733  cleanup:
2734     esxVI_ManagedObjectReference_Free(&managedObjectReference);
2735 
2736     return result;
2737 }
2738 
2739 
2740 
2741 int
esxVI_LookupVirtualMachineByName(esxVI_Context * ctx,const char * name,esxVI_String * propertyNameList,esxVI_ObjectContent ** virtualMachine,esxVI_Occurrence occurrence)2742 esxVI_LookupVirtualMachineByName(esxVI_Context *ctx, const char *name,
2743                                  esxVI_String *propertyNameList,
2744                                  esxVI_ObjectContent **virtualMachine,
2745                                  esxVI_Occurrence occurrence)
2746 {
2747     int result = -1;
2748     esxVI_String *completePropertyNameList = NULL;
2749     esxVI_ObjectContent *virtualMachineList = NULL;
2750     esxVI_ObjectContent *candidate = NULL;
2751 
2752     ESX_VI_CHECK_ARG_LIST(virtualMachine);
2753 
2754     if (esxVI_String_DeepCopyList(&completePropertyNameList,
2755                                   propertyNameList) < 0 ||
2756         esxVI_String_AppendValueToList(&completePropertyNameList, "name") < 0 ||
2757         esxVI_LookupVirtualMachineList(ctx, completePropertyNameList,
2758                                        &virtualMachineList) < 0) {
2759         goto cleanup;
2760     }
2761 
2762     for (candidate = virtualMachineList; candidate;
2763          candidate = candidate->_next) {
2764         g_autofree char *name_candidate = NULL;
2765 
2766         if (esxVI_GetVirtualMachineIdentity(candidate, NULL, &name_candidate,
2767                                             NULL) < 0) {
2768             goto cleanup;
2769         }
2770 
2771         if (STRNEQ(name, name_candidate))
2772             continue;
2773 
2774         if (esxVI_ObjectContent_DeepCopy(virtualMachine, candidate) < 0)
2775             goto cleanup;
2776 
2777         break;
2778     }
2779 
2780     if (!(*virtualMachine) && occurrence != esxVI_Occurrence_OptionalItem) {
2781         virReportError(VIR_ERR_NO_DOMAIN,
2782                        _("Could not find domain with name '%s'"), name);
2783         goto cleanup;
2784     }
2785 
2786     result = 0;
2787 
2788  cleanup:
2789     esxVI_String_Free(&completePropertyNameList);
2790     esxVI_ObjectContent_Free(&virtualMachineList);
2791     return result;
2792 }
2793 
2794 
2795 
2796 int
esxVI_LookupVirtualMachineByUuidAndPrepareForTask(esxVI_Context * ctx,const unsigned char * uuid,esxVI_String * propertyNameList,esxVI_ObjectContent ** virtualMachine,bool autoAnswer)2797 esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2798   (esxVI_Context *ctx, const unsigned char *uuid,
2799    esxVI_String *propertyNameList, esxVI_ObjectContent **virtualMachine,
2800    bool autoAnswer)
2801 {
2802     int result = -1;
2803     esxVI_String *completePropertyNameList = NULL;
2804     esxVI_VirtualMachineQuestionInfo *questionInfo = NULL;
2805     esxVI_TaskInfo *pendingTaskInfoList = NULL;
2806     bool blocked;
2807 
2808     if (esxVI_String_DeepCopyList(&completePropertyNameList,
2809                                   propertyNameList) < 0 ||
2810         esxVI_String_AppendValueListToList(&completePropertyNameList,
2811                                            "runtime.question\0"
2812                                            "recentTask\0") < 0 ||
2813         esxVI_LookupVirtualMachineByUuid(ctx, uuid, completePropertyNameList,
2814                                          virtualMachine,
2815                                          esxVI_Occurrence_RequiredItem) < 0 ||
2816         esxVI_GetVirtualMachineQuestionInfo(*virtualMachine,
2817                                             &questionInfo) < 0 ||
2818         esxVI_LookupPendingTaskInfoListByVirtualMachine
2819            (ctx, *virtualMachine, &pendingTaskInfoList) < 0) {
2820         goto cleanup;
2821     }
2822 
2823     if (questionInfo &&
2824         esxVI_HandleVirtualMachineQuestion(ctx, (*virtualMachine)->obj,
2825                                            questionInfo, autoAnswer,
2826                                            &blocked) < 0) {
2827         goto cleanup;
2828     }
2829 
2830     if (pendingTaskInfoList) {
2831         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2832                        _("Other tasks are pending for this domain"));
2833         goto cleanup;
2834     }
2835 
2836     result = 0;
2837 
2838  cleanup:
2839     esxVI_String_Free(&completePropertyNameList);
2840     esxVI_VirtualMachineQuestionInfo_Free(&questionInfo);
2841     esxVI_TaskInfo_Free(&pendingTaskInfoList);
2842 
2843     return result;
2844 }
2845 
2846 
2847 
2848 int
esxVI_LookupDatastoreList(esxVI_Context * ctx,esxVI_String * propertyNameList,esxVI_ObjectContent ** datastoreList)2849 esxVI_LookupDatastoreList(esxVI_Context *ctx, esxVI_String *propertyNameList,
2850                           esxVI_ObjectContent **datastoreList)
2851 {
2852     /* FIXME: Switch from ctx->hostSystem to ctx->computeResource for cluster
2853      *        support */
2854     return esxVI_LookupObjectContentByType(ctx, ctx->hostSystem->_reference,
2855                                            "Datastore", propertyNameList,
2856                                            datastoreList,
2857                                            esxVI_Occurrence_OptionalList);
2858 }
2859 
2860 
2861 
2862 int
esxVI_LookupDatastoreByName(esxVI_Context * ctx,const char * name,esxVI_String * propertyNameList,esxVI_ObjectContent ** datastore,esxVI_Occurrence occurrence)2863 esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
2864                             esxVI_String *propertyNameList,
2865                             esxVI_ObjectContent **datastore,
2866                             esxVI_Occurrence occurrence)
2867 {
2868     int result = -1;
2869     esxVI_String *completePropertyNameList = NULL;
2870     esxVI_ObjectContent *datastoreList = NULL;
2871     esxVI_ObjectContent *candidate = NULL;
2872     char *name_candidate;
2873 
2874     ESX_VI_CHECK_ARG_LIST(datastore);
2875 
2876     /* Get all datastores */
2877     if (esxVI_String_DeepCopyList(&completePropertyNameList,
2878                                   propertyNameList) < 0 ||
2879         esxVI_String_AppendValueToList(&completePropertyNameList,
2880                                        "summary.name") < 0 ||
2881         esxVI_LookupDatastoreList(ctx, completePropertyNameList,
2882                                   &datastoreList) < 0) {
2883         goto cleanup;
2884     }
2885 
2886     /* Search for a matching datastore */
2887     for (candidate = datastoreList; candidate;
2888          candidate = candidate->_next) {
2889         name_candidate = NULL;
2890 
2891         if (esxVI_GetStringValue(candidate, "summary.name", &name_candidate,
2892                                  esxVI_Occurrence_RequiredItem) < 0) {
2893             goto cleanup;
2894         }
2895 
2896         if (STREQ(name_candidate, name)) {
2897             if (esxVI_ObjectContent_DeepCopy(datastore, candidate) < 0)
2898                 goto cleanup;
2899 
2900             /* Found datastore with matching name */
2901             result = 0;
2902 
2903             goto cleanup;
2904         }
2905     }
2906 
2907     if (!(*datastore) && occurrence != esxVI_Occurrence_OptionalItem) {
2908         virReportError(VIR_ERR_INTERNAL_ERROR,
2909                        _("Could not find datastore with name '%s'"), name);
2910         goto cleanup;
2911     }
2912 
2913     result = 0;
2914 
2915  cleanup:
2916     esxVI_String_Free(&completePropertyNameList);
2917     esxVI_ObjectContent_Free(&datastoreList);
2918 
2919     return result;
2920 }
2921 
2922 
2923 int
esxVI_LookupDatastoreByAbsolutePath(esxVI_Context * ctx,const char * absolutePath,esxVI_String * propertyNameList,esxVI_ObjectContent ** datastore,esxVI_Occurrence occurrence)2924 esxVI_LookupDatastoreByAbsolutePath(esxVI_Context *ctx,
2925                                     const char *absolutePath,
2926                                     esxVI_String *propertyNameList,
2927                                     esxVI_ObjectContent **datastore,
2928                                     esxVI_Occurrence occurrence)
2929 {
2930     int result = -1;
2931     esxVI_String *completePropertyNameList = NULL;
2932     esxVI_ObjectContent *datastoreList = NULL;
2933     esxVI_ObjectContent *candidate = NULL;
2934     esxVI_DynamicProperty *dynamicProperty = NULL;
2935     esxVI_DatastoreHostMount *datastoreHostMountList = NULL;
2936     esxVI_DatastoreHostMount *datastoreHostMount = NULL;
2937 
2938     ESX_VI_CHECK_ARG_LIST(datastore);
2939 
2940     /* Get all datastores */
2941     if (esxVI_String_DeepCopyList(&completePropertyNameList,
2942                                   propertyNameList) < 0 ||
2943         esxVI_String_AppendValueToList(&completePropertyNameList, "host") < 0 ||
2944         esxVI_LookupDatastoreList(ctx, completePropertyNameList,
2945                                   &datastoreList) < 0) {
2946         goto cleanup;
2947     }
2948 
2949     /* Search for a matching datastore */
2950     for (candidate = datastoreList; candidate;
2951          candidate = candidate->_next) {
2952         esxVI_DatastoreHostMount_Free(&datastoreHostMountList);
2953 
2954         for (dynamicProperty = candidate->propSet; dynamicProperty;
2955              dynamicProperty = dynamicProperty->_next) {
2956             if (STREQ(dynamicProperty->name, "host")) {
2957                 if (esxVI_DatastoreHostMount_CastListFromAnyType
2958                       (dynamicProperty->val, &datastoreHostMountList) < 0) {
2959                     goto cleanup;
2960                 }
2961 
2962                 break;
2963             }
2964         }
2965 
2966         if (!datastoreHostMountList)
2967             continue;
2968 
2969         for (datastoreHostMount = datastoreHostMountList;
2970              datastoreHostMount;
2971              datastoreHostMount = datastoreHostMount->_next) {
2972             if (STRNEQ(ctx->hostSystem->_reference->value,
2973                        datastoreHostMount->key->value)) {
2974                 continue;
2975             }
2976 
2977             if (STRPREFIX(absolutePath, datastoreHostMount->mountInfo->path)) {
2978                 if (esxVI_ObjectContent_DeepCopy(datastore, candidate) < 0)
2979                     goto cleanup;
2980 
2981                 /* Found datastore with matching mount path */
2982                 result = 0;
2983 
2984                 goto cleanup;
2985             }
2986         }
2987     }
2988 
2989     if (!(*datastore) && occurrence != esxVI_Occurrence_OptionalItem) {
2990         virReportError(VIR_ERR_INTERNAL_ERROR,
2991                        _("Could not find datastore containing absolute path '%s'"),
2992                        absolutePath);
2993         goto cleanup;
2994     }
2995 
2996     result = 0;
2997 
2998  cleanup:
2999     esxVI_String_Free(&completePropertyNameList);
3000     esxVI_ObjectContent_Free(&datastoreList);
3001     esxVI_DatastoreHostMount_Free(&datastoreHostMountList);
3002 
3003     return result;
3004 }
3005 
3006 
3007 
3008 int
esxVI_LookupDatastoreHostMount(esxVI_Context * ctx,esxVI_ManagedObjectReference * datastore,esxVI_DatastoreHostMount ** hostMount,esxVI_Occurrence occurrence)3009 esxVI_LookupDatastoreHostMount(esxVI_Context *ctx,
3010                                esxVI_ManagedObjectReference *datastore,
3011                                esxVI_DatastoreHostMount **hostMount,
3012                                esxVI_Occurrence occurrence)
3013 {
3014     int result = -1;
3015     esxVI_String *propertyNameList = NULL;
3016     esxVI_ObjectContent *objectContent = NULL;
3017     esxVI_DynamicProperty *dynamicProperty = NULL;
3018     esxVI_DatastoreHostMount *hostMountList = NULL;
3019     esxVI_DatastoreHostMount *candidate = NULL;
3020 
3021     ESX_VI_CHECK_ARG_LIST(hostMount);
3022 
3023     if (esxVI_String_AppendValueToList(&propertyNameList, "host") < 0 ||
3024         esxVI_LookupObjectContentByType(ctx, datastore, "Datastore",
3025                                         propertyNameList, &objectContent,
3026                                         esxVI_Occurrence_RequiredItem) < 0) {
3027         goto cleanup;
3028     }
3029 
3030     for (dynamicProperty = objectContent->propSet; dynamicProperty;
3031          dynamicProperty = dynamicProperty->_next) {
3032         if (STREQ(dynamicProperty->name, "host")) {
3033             if (esxVI_DatastoreHostMount_CastListFromAnyType
3034                   (dynamicProperty->val, &hostMountList) < 0) {
3035                 goto cleanup;
3036             }
3037 
3038             break;
3039         } else {
3040             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3041         }
3042     }
3043 
3044     for (candidate = hostMountList; candidate;
3045          candidate = candidate->_next) {
3046         if (STRNEQ(ctx->hostSystem->_reference->value, candidate->key->value))
3047             continue;
3048 
3049         if (esxVI_DatastoreHostMount_DeepCopy(hostMount, candidate) < 0)
3050             goto cleanup;
3051 
3052         break;
3053     }
3054 
3055     if (!(*hostMount) && occurrence == esxVI_Occurrence_RequiredItem) {
3056         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3057                        _("Could not lookup datastore host mount"));
3058         goto cleanup;
3059     }
3060 
3061     result = 0;
3062 
3063  cleanup:
3064     esxVI_String_Free(&propertyNameList);
3065     esxVI_ObjectContent_Free(&objectContent);
3066     esxVI_DatastoreHostMount_Free(&hostMountList);
3067 
3068     return result;
3069 }
3070 
3071 
3072 int
esxVI_LookupTaskInfoByTask(esxVI_Context * ctx,esxVI_ManagedObjectReference * task,esxVI_TaskInfo ** taskInfo)3073 esxVI_LookupTaskInfoByTask(esxVI_Context *ctx,
3074                            esxVI_ManagedObjectReference *task,
3075                            esxVI_TaskInfo **taskInfo)
3076 {
3077     int result = -1;
3078     esxVI_String *propertyNameList = NULL;
3079     esxVI_ObjectContent *objectContent = NULL;
3080     esxVI_DynamicProperty *dynamicProperty = NULL;
3081 
3082     ESX_VI_CHECK_ARG_LIST(taskInfo);
3083 
3084     if (esxVI_String_AppendValueToList(&propertyNameList, "info") < 0 ||
3085         esxVI_LookupObjectContentByType(ctx, task, "Task", propertyNameList,
3086                                         &objectContent,
3087                                         esxVI_Occurrence_RequiredItem) < 0) {
3088         goto cleanup;
3089     }
3090 
3091     for (dynamicProperty = objectContent->propSet; dynamicProperty;
3092          dynamicProperty = dynamicProperty->_next) {
3093         if (STREQ(dynamicProperty->name, "info")) {
3094             if (esxVI_TaskInfo_CastFromAnyType(dynamicProperty->val,
3095                                                taskInfo) < 0) {
3096                 goto cleanup;
3097             }
3098 
3099             result = 0;
3100             break;
3101         } else {
3102             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3103         }
3104     }
3105 
3106  cleanup:
3107     esxVI_String_Free(&propertyNameList);
3108     esxVI_ObjectContent_Free(&objectContent);
3109 
3110     return result;
3111 }
3112 
3113 
3114 
3115 int
esxVI_LookupPendingTaskInfoListByVirtualMachine(esxVI_Context * ctx,esxVI_ObjectContent * virtualMachine,esxVI_TaskInfo ** pendingTaskInfoList)3116 esxVI_LookupPendingTaskInfoListByVirtualMachine
3117   (esxVI_Context *ctx, esxVI_ObjectContent *virtualMachine,
3118    esxVI_TaskInfo **pendingTaskInfoList)
3119 {
3120     int result = -1;
3121     esxVI_String *propertyNameList = NULL;
3122     esxVI_ManagedObjectReference *recentTaskList = NULL;
3123     esxVI_ManagedObjectReference *recentTask = NULL;
3124     esxVI_DynamicProperty *dynamicProperty = NULL;
3125     esxVI_TaskInfo *taskInfo = NULL;
3126 
3127     ESX_VI_CHECK_ARG_LIST(pendingTaskInfoList);
3128 
3129     /* Get list of recent tasks */
3130     for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
3131          dynamicProperty = dynamicProperty->_next) {
3132         if (STREQ(dynamicProperty->name, "recentTask")) {
3133             if (esxVI_ManagedObjectReference_CastListFromAnyType
3134                   (dynamicProperty->val, &recentTaskList) < 0) {
3135                 goto cleanup;
3136             }
3137 
3138             break;
3139         }
3140     }
3141 
3142     /* Lookup task info for each task */
3143     for (recentTask = recentTaskList; recentTask;
3144          recentTask = recentTask->_next) {
3145         if (esxVI_LookupTaskInfoByTask(ctx, recentTask, &taskInfo) < 0)
3146             goto cleanup;
3147 
3148         if (taskInfo->state == esxVI_TaskInfoState_Queued ||
3149             taskInfo->state == esxVI_TaskInfoState_Running) {
3150             if (esxVI_TaskInfo_AppendToList(pendingTaskInfoList,
3151                                             taskInfo) < 0) {
3152                 goto cleanup;
3153             }
3154 
3155             taskInfo = NULL;
3156         } else {
3157             esxVI_TaskInfo_Free(&taskInfo);
3158         }
3159     }
3160 
3161     result = 0;
3162 
3163  cleanup:
3164     if (result < 0)
3165         esxVI_TaskInfo_Free(pendingTaskInfoList);
3166 
3167     esxVI_String_Free(&propertyNameList);
3168     esxVI_ManagedObjectReference_Free(&recentTaskList);
3169     esxVI_TaskInfo_Free(&taskInfo);
3170 
3171     return result;
3172 }
3173 
3174 
3175 
3176 int
esxVI_LookupAndHandleVirtualMachineQuestion(esxVI_Context * ctx,const unsigned char * uuid,esxVI_Occurrence occurrence,bool autoAnswer,bool * blocked)3177 esxVI_LookupAndHandleVirtualMachineQuestion(esxVI_Context *ctx,
3178                                             const unsigned char *uuid,
3179                                             esxVI_Occurrence occurrence,
3180                                             bool autoAnswer, bool *blocked)
3181 {
3182     int result = -1;
3183     esxVI_ObjectContent *virtualMachine = NULL;
3184     esxVI_String *propertyNameList = NULL;
3185     esxVI_VirtualMachineQuestionInfo *questionInfo = NULL;
3186 
3187     if (esxVI_String_AppendValueToList(&propertyNameList,
3188                                        "runtime.question") < 0 ||
3189         esxVI_LookupVirtualMachineByUuid(ctx, uuid, propertyNameList,
3190                                          &virtualMachine, occurrence) < 0) {
3191         goto cleanup;
3192     }
3193 
3194     if (virtualMachine) {
3195         if (esxVI_GetVirtualMachineQuestionInfo(virtualMachine,
3196                                                 &questionInfo) < 0) {
3197             goto cleanup;
3198         }
3199 
3200         if (questionInfo &&
3201             esxVI_HandleVirtualMachineQuestion(ctx, virtualMachine->obj,
3202                                                questionInfo, autoAnswer,
3203                                                blocked) < 0) {
3204             goto cleanup;
3205         }
3206     }
3207 
3208     result = 0;
3209 
3210  cleanup:
3211     esxVI_ObjectContent_Free(&virtualMachine);
3212     esxVI_String_Free(&propertyNameList);
3213     esxVI_VirtualMachineQuestionInfo_Free(&questionInfo);
3214 
3215     return result;
3216 }
3217 
3218 
3219 
3220 int
esxVI_LookupRootSnapshotTreeList(esxVI_Context * ctx,const unsigned char * virtualMachineUuid,esxVI_VirtualMachineSnapshotTree ** rootSnapshotTreeList)3221 esxVI_LookupRootSnapshotTreeList
3222   (esxVI_Context *ctx, const unsigned char *virtualMachineUuid,
3223    esxVI_VirtualMachineSnapshotTree **rootSnapshotTreeList)
3224 {
3225     int result = -1;
3226     esxVI_String *propertyNameList = NULL;
3227     esxVI_ObjectContent *virtualMachine = NULL;
3228     esxVI_DynamicProperty *dynamicProperty = NULL;
3229 
3230     ESX_VI_CHECK_ARG_LIST(rootSnapshotTreeList);
3231 
3232     if (esxVI_String_AppendValueToList(&propertyNameList,
3233                                        "snapshot.rootSnapshotList") < 0 ||
3234         esxVI_LookupVirtualMachineByUuid(ctx, virtualMachineUuid,
3235                                          propertyNameList, &virtualMachine,
3236                                          esxVI_Occurrence_RequiredItem) < 0) {
3237         goto cleanup;
3238     }
3239 
3240     for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
3241          dynamicProperty = dynamicProperty->_next) {
3242         if (STREQ(dynamicProperty->name, "snapshot.rootSnapshotList")) {
3243             if (esxVI_VirtualMachineSnapshotTree_CastListFromAnyType
3244                   (dynamicProperty->val, rootSnapshotTreeList) < 0) {
3245                 goto cleanup;
3246             }
3247 
3248             break;
3249         } else {
3250             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3251         }
3252     }
3253 
3254     result = 0;
3255 
3256  cleanup:
3257     if (result < 0)
3258         esxVI_VirtualMachineSnapshotTree_Free(rootSnapshotTreeList);
3259 
3260     esxVI_String_Free(&propertyNameList);
3261     esxVI_ObjectContent_Free(&virtualMachine);
3262 
3263     return result;
3264 }
3265 
3266 
3267 
3268 int
esxVI_LookupCurrentSnapshotTree(esxVI_Context * ctx,const unsigned char * virtualMachineUuid,esxVI_VirtualMachineSnapshotTree ** currentSnapshotTree,esxVI_Occurrence occurrence)3269 esxVI_LookupCurrentSnapshotTree
3270   (esxVI_Context *ctx, const unsigned char *virtualMachineUuid,
3271    esxVI_VirtualMachineSnapshotTree **currentSnapshotTree,
3272    esxVI_Occurrence occurrence)
3273 {
3274     int result = -1;
3275     esxVI_String *propertyNameList = NULL;
3276     esxVI_ObjectContent *virtualMachine = NULL;
3277     esxVI_DynamicProperty *dynamicProperty = NULL;
3278     esxVI_ManagedObjectReference *currentSnapshot = NULL;
3279     esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
3280     esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
3281 
3282     ESX_VI_CHECK_ARG_LIST(currentSnapshotTree);
3283 
3284     if (esxVI_String_AppendValueListToList(&propertyNameList,
3285                                            "snapshot.currentSnapshot\0"
3286                                            "snapshot.rootSnapshotList\0") < 0 ||
3287         esxVI_LookupVirtualMachineByUuid(ctx, virtualMachineUuid,
3288                                          propertyNameList, &virtualMachine,
3289                                          esxVI_Occurrence_RequiredItem) < 0) {
3290         goto cleanup;
3291     }
3292 
3293     for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
3294          dynamicProperty = dynamicProperty->_next) {
3295         if (STREQ(dynamicProperty->name, "snapshot.currentSnapshot")) {
3296             if (esxVI_ManagedObjectReference_CastFromAnyType
3297                   (dynamicProperty->val, &currentSnapshot) < 0) {
3298                 goto cleanup;
3299             }
3300         } else if (STREQ(dynamicProperty->name, "snapshot.rootSnapshotList")) {
3301             if (esxVI_VirtualMachineSnapshotTree_CastListFromAnyType
3302                   (dynamicProperty->val, &rootSnapshotTreeList) < 0) {
3303                 goto cleanup;
3304             }
3305         } else {
3306             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3307         }
3308     }
3309 
3310     if (!currentSnapshot) {
3311         if (occurrence == esxVI_Occurrence_OptionalItem) {
3312             result = 0;
3313 
3314             goto cleanup;
3315         } else {
3316             virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
3317                            _("Domain has no current snapshot"));
3318             goto cleanup;
3319         }
3320     }
3321 
3322     if (!rootSnapshotTreeList) {
3323         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3324                        _("Could not lookup root snapshot list"));
3325         goto cleanup;
3326     }
3327 
3328     if (esxVI_GetSnapshotTreeBySnapshot(rootSnapshotTreeList, currentSnapshot,
3329                                         &snapshotTree) < 0 ||
3330         esxVI_VirtualMachineSnapshotTree_DeepCopy(currentSnapshotTree,
3331                                                   snapshotTree) < 0) {
3332         goto cleanup;
3333     }
3334 
3335     result = 0;
3336 
3337  cleanup:
3338     esxVI_String_Free(&propertyNameList);
3339     esxVI_ObjectContent_Free(&virtualMachine);
3340     esxVI_ManagedObjectReference_Free(&currentSnapshot);
3341     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
3342 
3343     return result;
3344 }
3345 
3346 
3347 
3348 int
esxVI_LookupFileInfoByDatastorePath(esxVI_Context * ctx,const char * datastorePath,bool lookupFolder,esxVI_FileInfo ** fileInfo,esxVI_Occurrence occurrence)3349 esxVI_LookupFileInfoByDatastorePath(esxVI_Context *ctx,
3350                                     const char *datastorePath,
3351                                     bool lookupFolder,
3352                                     esxVI_FileInfo **fileInfo,
3353                                     esxVI_Occurrence occurrence)
3354 {
3355     int result = -1;
3356     g_autofree char *datastoreName = NULL;
3357     g_autofree char *directoryName = NULL;
3358     g_autofree char *directoryAndFileName = NULL;
3359     g_autofree char *fileName = NULL;
3360     size_t length;
3361     g_autofree char *datastorePathWithoutFileName = NULL;
3362     esxVI_String *propertyNameList = NULL;
3363     esxVI_ObjectContent *datastore = NULL;
3364     esxVI_ManagedObjectReference *hostDatastoreBrowser = NULL;
3365     esxVI_HostDatastoreBrowserSearchSpec *searchSpec = NULL;
3366     esxVI_FolderFileQuery *folderFileQuery = NULL;
3367     esxVI_VmDiskFileQuery *vmDiskFileQuery = NULL;
3368     esxVI_IsoImageFileQuery *isoImageFileQuery = NULL;
3369     esxVI_FloppyImageFileQuery *floppyImageFileQuery = NULL;
3370     esxVI_ManagedObjectReference *task = NULL;
3371     esxVI_TaskInfoState taskInfoState;
3372     g_autofree char *taskInfoErrorMessage = NULL;
3373     esxVI_TaskInfo *taskInfo = NULL;
3374     esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
3375 
3376     ESX_VI_CHECK_ARG_LIST(fileInfo);
3377 
3378     if (esxUtil_ParseDatastorePath(datastorePath, &datastoreName,
3379                                    &directoryName, &directoryAndFileName) < 0) {
3380         goto cleanup;
3381     }
3382 
3383     if (STREQ(directoryName, directoryAndFileName)) {
3384         /*
3385          * The <path> part of the datastore path didn't contain a '/', assume
3386          * that the <path> part is actually the file name.
3387          */
3388         datastorePathWithoutFileName = g_strdup_printf("[%s]", datastoreName);
3389 
3390         fileName = g_strdup(directoryAndFileName);
3391     } else {
3392         datastorePathWithoutFileName = g_strdup_printf("[%s] %s", datastoreName,
3393                                                        directoryName);
3394 
3395         length = strlen(directoryName);
3396 
3397         if (directoryAndFileName[length] != '/' ||
3398             directoryAndFileName[length + 1] == '\0') {
3399             virReportError(VIR_ERR_INTERNAL_ERROR,
3400                            _("Datastore path '%s' doesn't reference a file"),
3401                            datastorePath);
3402             goto cleanup;
3403         }
3404 
3405         fileName = g_strdup(directoryAndFileName + length + 1);
3406     }
3407 
3408     /* Lookup HostDatastoreBrowser */
3409     if (esxVI_String_AppendValueToList(&propertyNameList, "browser") < 0 ||
3410         esxVI_LookupDatastoreByName(ctx, datastoreName, propertyNameList,
3411                                     &datastore,
3412                                     esxVI_Occurrence_RequiredItem) < 0 ||
3413         esxVI_GetManagedObjectReference(datastore, "browser",
3414                                         &hostDatastoreBrowser,
3415                                         esxVI_Occurrence_RequiredItem) < 0) {
3416         goto cleanup;
3417     }
3418 
3419     /* Build HostDatastoreBrowserSearchSpec */
3420     if (esxVI_HostDatastoreBrowserSearchSpec_Alloc(&searchSpec) < 0 ||
3421         esxVI_FileQueryFlags_Alloc(&searchSpec->details) < 0) {
3422         goto cleanup;
3423     }
3424 
3425     searchSpec->details->fileType = esxVI_Boolean_True;
3426     searchSpec->details->fileSize = esxVI_Boolean_True;
3427     searchSpec->details->modification = esxVI_Boolean_False;
3428 
3429     if (lookupFolder) {
3430         if (esxVI_FolderFileQuery_Alloc(&folderFileQuery) < 0 ||
3431             esxVI_FileQuery_AppendToList
3432               (&searchSpec->query,
3433                esxVI_FileQuery_DynamicCast(folderFileQuery)) < 0) {
3434             goto cleanup;
3435         }
3436         folderFileQuery = NULL;
3437     } else {
3438         if (esxVI_VmDiskFileQuery_Alloc(&vmDiskFileQuery) < 0 ||
3439             esxVI_VmDiskFileQueryFlags_Alloc(&vmDiskFileQuery->details) < 0 ||
3440             esxVI_FileQuery_AppendToList
3441               (&searchSpec->query,
3442                esxVI_FileQuery_DynamicCast(vmDiskFileQuery)) < 0) {
3443             goto cleanup;
3444         }
3445 
3446         vmDiskFileQuery->details->diskType = esxVI_Boolean_False;
3447         vmDiskFileQuery->details->capacityKb = esxVI_Boolean_True;
3448         vmDiskFileQuery->details->hardwareVersion = esxVI_Boolean_False;
3449         vmDiskFileQuery->details->controllerType = esxVI_Boolean_True;
3450         vmDiskFileQuery->details->diskExtents = esxVI_Boolean_False;
3451         vmDiskFileQuery = NULL;
3452 
3453         if (esxVI_IsoImageFileQuery_Alloc(&isoImageFileQuery) < 0 ||
3454             esxVI_FileQuery_AppendToList
3455               (&searchSpec->query,
3456                esxVI_FileQuery_DynamicCast(isoImageFileQuery)) < 0) {
3457             goto cleanup;
3458         }
3459         isoImageFileQuery = NULL;
3460 
3461         if (esxVI_FloppyImageFileQuery_Alloc(&floppyImageFileQuery) < 0 ||
3462             esxVI_FileQuery_AppendToList
3463               (&searchSpec->query,
3464                esxVI_FileQuery_DynamicCast(floppyImageFileQuery)) < 0) {
3465             goto cleanup;
3466         }
3467         floppyImageFileQuery = NULL;
3468     }
3469 
3470     if (esxVI_String_Alloc(&searchSpec->matchPattern) < 0)
3471         goto cleanup;
3472 
3473     searchSpec->matchPattern->value = fileName;
3474 
3475     /* Search datastore for file */
3476     if (esxVI_SearchDatastore_Task(ctx, hostDatastoreBrowser,
3477                                    datastorePathWithoutFileName, searchSpec,
3478                                    &task) < 0 ||
3479         esxVI_WaitForTaskCompletion(ctx, task, NULL, esxVI_Occurrence_None,
3480                                     false, &taskInfoState,
3481                                     &taskInfoErrorMessage) < 0) {
3482         goto cleanup;
3483     }
3484 
3485     if (taskInfoState != esxVI_TaskInfoState_Success) {
3486         virReportError(VIR_ERR_INTERNAL_ERROR,
3487                        _("Could not search in datastore '%s': %s"),
3488                        datastoreName, taskInfoErrorMessage);
3489         goto cleanup;
3490     }
3491 
3492     if (esxVI_LookupTaskInfoByTask(ctx, task, &taskInfo) < 0 ||
3493         esxVI_HostDatastoreBrowserSearchResults_CastFromAnyType
3494           (taskInfo->result, &searchResults) < 0) {
3495         goto cleanup;
3496     }
3497 
3498     /* Interpret search result */
3499     if (!searchResults->file) {
3500         if (occurrence == esxVI_Occurrence_OptionalItem) {
3501             result = 0;
3502 
3503             goto cleanup;
3504         } else {
3505             virReportError(VIR_ERR_NO_STORAGE_VOL,
3506                            _("No storage volume with key or path '%s'"),
3507                            datastorePath);
3508             goto cleanup;
3509         }
3510     }
3511 
3512     *fileInfo = g_steal_pointer(&searchResults->file);
3513 
3514     result = 0;
3515 
3516  cleanup:
3517     /* Don't double free fileName */
3518     if (searchSpec && searchSpec->matchPattern)
3519         searchSpec->matchPattern->value = NULL;
3520 
3521     esxVI_String_Free(&propertyNameList);
3522     esxVI_ObjectContent_Free(&datastore);
3523     esxVI_ManagedObjectReference_Free(&hostDatastoreBrowser);
3524     esxVI_HostDatastoreBrowserSearchSpec_Free(&searchSpec);
3525     esxVI_ManagedObjectReference_Free(&task);
3526     esxVI_TaskInfo_Free(&taskInfo);
3527     esxVI_HostDatastoreBrowserSearchResults_Free(&searchResults);
3528     esxVI_FolderFileQuery_Free(&folderFileQuery);
3529     esxVI_VmDiskFileQuery_Free(&vmDiskFileQuery);
3530     esxVI_IsoImageFileQuery_Free(&isoImageFileQuery);
3531     esxVI_FloppyImageFileQuery_Free(&floppyImageFileQuery);
3532 
3533     return result;
3534 }
3535 
3536 
3537 
3538 int
esxVI_LookupDatastoreContentByDatastoreName(esxVI_Context * ctx,const char * datastoreName,esxVI_HostDatastoreBrowserSearchResults ** searchResultsList)3539 esxVI_LookupDatastoreContentByDatastoreName
3540   (esxVI_Context *ctx, const char *datastoreName,
3541    esxVI_HostDatastoreBrowserSearchResults **searchResultsList)
3542 {
3543     int result = -1;
3544     esxVI_String *propertyNameList = NULL;
3545     esxVI_ObjectContent *datastore = NULL;
3546     esxVI_ManagedObjectReference *hostDatastoreBrowser = NULL;
3547     esxVI_HostDatastoreBrowserSearchSpec *searchSpec = NULL;
3548     esxVI_VmDiskFileQuery *vmDiskFileQuery = NULL;
3549     esxVI_IsoImageFileQuery *isoImageFileQuery = NULL;
3550     esxVI_FloppyImageFileQuery *floppyImageFileQuery = NULL;
3551     g_autofree char *datastorePath = NULL;
3552     esxVI_ManagedObjectReference *task = NULL;
3553     esxVI_TaskInfoState taskInfoState;
3554     g_autofree char *taskInfoErrorMessage = NULL;
3555     esxVI_TaskInfo *taskInfo = NULL;
3556 
3557     ESX_VI_CHECK_ARG_LIST(searchResultsList);
3558 
3559     /* Lookup Datastore and HostDatastoreBrowser */
3560     if (esxVI_String_AppendValueToList(&propertyNameList, "browser") < 0 ||
3561         esxVI_LookupDatastoreByName(ctx, datastoreName, propertyNameList,
3562                                     &datastore,
3563                                     esxVI_Occurrence_RequiredItem) < 0 ||
3564         esxVI_GetManagedObjectReference(datastore, "browser",
3565                                         &hostDatastoreBrowser,
3566                                         esxVI_Occurrence_RequiredItem) < 0) {
3567         goto cleanup;
3568     }
3569 
3570     /* Build HostDatastoreBrowserSearchSpec */
3571     if (esxVI_HostDatastoreBrowserSearchSpec_Alloc(&searchSpec) < 0 ||
3572         esxVI_FileQueryFlags_Alloc(&searchSpec->details) < 0) {
3573         goto cleanup;
3574     }
3575 
3576     searchSpec->details->fileType = esxVI_Boolean_True;
3577     searchSpec->details->fileSize = esxVI_Boolean_True;
3578     searchSpec->details->modification = esxVI_Boolean_False;
3579 
3580     if (esxVI_VmDiskFileQuery_Alloc(&vmDiskFileQuery) < 0 ||
3581         esxVI_VmDiskFileQueryFlags_Alloc(&vmDiskFileQuery->details) < 0 ||
3582         esxVI_FileQuery_AppendToList
3583           (&searchSpec->query,
3584            esxVI_FileQuery_DynamicCast(vmDiskFileQuery)) < 0) {
3585         goto cleanup;
3586     }
3587 
3588     vmDiskFileQuery->details->diskType = esxVI_Boolean_False;
3589     vmDiskFileQuery->details->capacityKb = esxVI_Boolean_True;
3590     vmDiskFileQuery->details->hardwareVersion = esxVI_Boolean_False;
3591     vmDiskFileQuery->details->controllerType = esxVI_Boolean_True;
3592     vmDiskFileQuery->details->diskExtents = esxVI_Boolean_False;
3593     vmDiskFileQuery = NULL;
3594 
3595     if (esxVI_IsoImageFileQuery_Alloc(&isoImageFileQuery) < 0 ||
3596         esxVI_FileQuery_AppendToList
3597           (&searchSpec->query,
3598            esxVI_FileQuery_DynamicCast(isoImageFileQuery)) < 0) {
3599         goto cleanup;
3600     }
3601     isoImageFileQuery = NULL;
3602 
3603     if (esxVI_FloppyImageFileQuery_Alloc(&floppyImageFileQuery) < 0 ||
3604         esxVI_FileQuery_AppendToList
3605           (&searchSpec->query,
3606            esxVI_FileQuery_DynamicCast(floppyImageFileQuery)) < 0) {
3607         goto cleanup;
3608     }
3609     floppyImageFileQuery = NULL;
3610 
3611     /* Search datastore for files */
3612     datastorePath = g_strdup_printf("[%s]", datastoreName);
3613 
3614     if (esxVI_SearchDatastoreSubFolders_Task(ctx, hostDatastoreBrowser,
3615                                              datastorePath, searchSpec,
3616                                              &task) < 0 ||
3617         esxVI_WaitForTaskCompletion(ctx, task, NULL, esxVI_Occurrence_None,
3618                                     false, &taskInfoState,
3619                                     &taskInfoErrorMessage) < 0) {
3620         goto cleanup;
3621     }
3622 
3623     if (taskInfoState != esxVI_TaskInfoState_Success) {
3624         virReportError(VIR_ERR_INTERNAL_ERROR,
3625                        _("Could not search in datastore '%s': %s"),
3626                        datastoreName, taskInfoErrorMessage);
3627         goto cleanup;
3628     }
3629 
3630     if (esxVI_LookupTaskInfoByTask(ctx, task, &taskInfo) < 0 ||
3631         esxVI_HostDatastoreBrowserSearchResults_CastListFromAnyType
3632           (taskInfo->result, searchResultsList) < 0) {
3633         goto cleanup;
3634     }
3635 
3636     result = 0;
3637 
3638  cleanup:
3639     esxVI_String_Free(&propertyNameList);
3640     esxVI_ObjectContent_Free(&datastore);
3641     esxVI_ManagedObjectReference_Free(&hostDatastoreBrowser);
3642     esxVI_HostDatastoreBrowserSearchSpec_Free(&searchSpec);
3643     esxVI_ManagedObjectReference_Free(&task);
3644     esxVI_TaskInfo_Free(&taskInfo);
3645     esxVI_VmDiskFileQuery_Free(&vmDiskFileQuery);
3646     esxVI_IsoImageFileQuery_Free(&isoImageFileQuery);
3647     esxVI_FloppyImageFileQuery_Free(&floppyImageFileQuery);
3648 
3649     return result;
3650 }
3651 
3652 
3653 
3654 int
esxVI_LookupStorageVolumeKeyByDatastorePath(esxVI_Context * ctx,const char * datastorePath,char ** key)3655 esxVI_LookupStorageVolumeKeyByDatastorePath(esxVI_Context *ctx,
3656                                             const char *datastorePath,
3657                                             char **key)
3658 {
3659     int result = -1;
3660     esxVI_FileInfo *fileInfo = NULL;
3661     g_autofree char *uuid_string = NULL;
3662 
3663     ESX_VI_CHECK_ARG_LIST(key);
3664 
3665     if (ctx->hasQueryVirtualDiskUuid) {
3666         if (esxVI_LookupFileInfoByDatastorePath
3667               (ctx, datastorePath, false, &fileInfo,
3668                esxVI_Occurrence_RequiredItem) < 0) {
3669             goto cleanup;
3670         }
3671 
3672         if (esxVI_VmDiskFileInfo_DynamicCast(fileInfo)) {
3673             /* VirtualDisks have a UUID, use it as key */
3674             if (esxVI_QueryVirtualDiskUuid(ctx, datastorePath,
3675                                            ctx->datacenter->_reference,
3676                                            &uuid_string) < 0) {
3677                 goto cleanup;
3678             }
3679 
3680             *key = g_new0(char, VIR_UUID_STRING_BUFLEN);
3681 
3682             if (esxUtil_ReformatUuid(uuid_string, *key) < 0)
3683                 goto cleanup;
3684         }
3685     }
3686 
3687     if (!(*key)) {
3688         /* Other files don't have a UUID, fall back to the path as key */
3689         *key = g_strdup(datastorePath);
3690     }
3691 
3692     result = 0;
3693 
3694  cleanup:
3695     esxVI_FileInfo_Free(&fileInfo);
3696     return result;
3697 }
3698 
3699 
3700 
3701 int
esxVI_LookupAutoStartDefaults(esxVI_Context * ctx,esxVI_AutoStartDefaults ** defaults)3702 esxVI_LookupAutoStartDefaults(esxVI_Context *ctx,
3703                               esxVI_AutoStartDefaults **defaults)
3704 {
3705     int result = -1;
3706     esxVI_String *propertyNameList = NULL;
3707     esxVI_ObjectContent *hostAutoStartManager = NULL;
3708     esxVI_DynamicProperty *dynamicProperty = NULL;
3709 
3710     ESX_VI_CHECK_ARG_LIST(defaults);
3711 
3712     /*
3713      * Lookup HostAutoStartManagerConfig from the HostAutoStartManager because
3714      * for some reason this is much faster than looking up the same info from
3715      * the HostSystem config.
3716      */
3717     if (esxVI_String_AppendValueToList(&propertyNameList,
3718                                        "config.defaults") < 0 ||
3719         esxVI_LookupObjectContentByType
3720           (ctx, ctx->hostSystem->configManager->autoStartManager,
3721            "HostAutoStartManager", propertyNameList,
3722            &hostAutoStartManager, esxVI_Occurrence_RequiredItem) < 0) {
3723         goto cleanup;
3724     }
3725 
3726     for (dynamicProperty = hostAutoStartManager->propSet;
3727          dynamicProperty; dynamicProperty = dynamicProperty->_next) {
3728         if (STREQ(dynamicProperty->name, "config.defaults")) {
3729             if (esxVI_AutoStartDefaults_CastFromAnyType(dynamicProperty->val,
3730                                                         defaults) < 0) {
3731                 goto cleanup;
3732             }
3733 
3734             break;
3735         }
3736     }
3737 
3738     if (!(*defaults)) {
3739         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3740                        _("Could not retrieve the AutoStartDefaults object"));
3741         goto cleanup;
3742     }
3743 
3744     result = 0;
3745 
3746  cleanup:
3747     esxVI_String_Free(&propertyNameList);
3748     esxVI_ObjectContent_Free(&hostAutoStartManager);
3749 
3750     return result;
3751 }
3752 
3753 
3754 
3755 int
esxVI_LookupAutoStartPowerInfoList(esxVI_Context * ctx,esxVI_AutoStartPowerInfo ** powerInfoList)3756 esxVI_LookupAutoStartPowerInfoList(esxVI_Context *ctx,
3757                                    esxVI_AutoStartPowerInfo **powerInfoList)
3758 {
3759     int result = -1;
3760     esxVI_String *propertyNameList = NULL;
3761     esxVI_ObjectContent *hostAutoStartManager = NULL;
3762     esxVI_DynamicProperty *dynamicProperty = NULL;
3763 
3764     ESX_VI_CHECK_ARG_LIST(powerInfoList);
3765 
3766     /*
3767      * Lookup HostAutoStartManagerConfig from the HostAutoStartManager because
3768      * for some reason this is much faster than looking up the same info from
3769      * the HostSystem config.
3770      */
3771     if (esxVI_String_AppendValueToList(&propertyNameList,
3772                                        "config.powerInfo") < 0 ||
3773         esxVI_LookupObjectContentByType
3774           (ctx, ctx->hostSystem->configManager->autoStartManager,
3775            "HostAutoStartManager", propertyNameList,
3776            &hostAutoStartManager, esxVI_Occurrence_RequiredItem) < 0) {
3777         goto cleanup;
3778     }
3779 
3780     for (dynamicProperty = hostAutoStartManager->propSet;
3781          dynamicProperty; dynamicProperty = dynamicProperty->_next) {
3782         if (STREQ(dynamicProperty->name, "config.powerInfo")) {
3783             if (esxVI_AutoStartPowerInfo_CastListFromAnyType
3784                   (dynamicProperty->val, powerInfoList) < 0) {
3785                 goto cleanup;
3786             }
3787 
3788             break;
3789         }
3790     }
3791 
3792     result = 0;
3793 
3794  cleanup:
3795     esxVI_String_Free(&propertyNameList);
3796     esxVI_ObjectContent_Free(&hostAutoStartManager);
3797 
3798     return result;
3799 }
3800 
3801 
3802 
3803 int
esxVI_LookupPhysicalNicList(esxVI_Context * ctx,esxVI_PhysicalNic ** physicalNicList)3804 esxVI_LookupPhysicalNicList(esxVI_Context *ctx,
3805                             esxVI_PhysicalNic **physicalNicList)
3806 {
3807     int result = -1;
3808     esxVI_String *propertyNameList = NULL;
3809     esxVI_ObjectContent *hostSystem = NULL;
3810     esxVI_DynamicProperty *dynamicProperty = NULL;
3811 
3812     ESX_VI_CHECK_ARG_LIST(physicalNicList);
3813 
3814     if (esxVI_String_AppendValueToList(&propertyNameList,
3815                                        "config.network.pnic") < 0 ||
3816         esxVI_LookupHostSystemProperties(ctx, propertyNameList,
3817                                          &hostSystem) < 0) {
3818         goto cleanup;
3819     }
3820 
3821     for (dynamicProperty = hostSystem->propSet; dynamicProperty;
3822          dynamicProperty = dynamicProperty->_next) {
3823         if (STREQ(dynamicProperty->name, "config.network.pnic")) {
3824             if (esxVI_PhysicalNic_CastListFromAnyType(dynamicProperty->val,
3825                                                       physicalNicList) < 0) {
3826                 goto cleanup;
3827             }
3828         } else {
3829             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3830         }
3831     }
3832 
3833     result = 0;
3834 
3835  cleanup:
3836     esxVI_String_Free(&propertyNameList);
3837     esxVI_ObjectContent_Free(&hostSystem);
3838 
3839     return result;
3840 }
3841 
3842 
3843 
3844 int
esxVI_LookupPhysicalNicByName(esxVI_Context * ctx,const char * name,esxVI_PhysicalNic ** physicalNic,esxVI_Occurrence occurrence)3845 esxVI_LookupPhysicalNicByName(esxVI_Context *ctx, const char *name,
3846                               esxVI_PhysicalNic **physicalNic,
3847                               esxVI_Occurrence occurrence)
3848 {
3849     int result = -1;
3850     esxVI_PhysicalNic *physicalNicList = NULL;
3851     esxVI_PhysicalNic *candidate = NULL;
3852 
3853     ESX_VI_CHECK_ARG_LIST(physicalNic);
3854 
3855     if (esxVI_LookupPhysicalNicList(ctx, &physicalNicList) < 0)
3856         goto cleanup;
3857 
3858     /* Search for a matching physical NIC */
3859     for (candidate = physicalNicList; candidate;
3860          candidate = candidate->_next) {
3861         if (STRCASEEQ(candidate->device, name)) {
3862             if (esxVI_PhysicalNic_DeepCopy(physicalNic, candidate) < 0)
3863                 goto cleanup;
3864 
3865             /* Found physical NIC with matching name */
3866             result = 0;
3867 
3868             goto cleanup;
3869         }
3870     }
3871 
3872     if (!(*physicalNic) && occurrence != esxVI_Occurrence_OptionalItem) {
3873         virReportError(VIR_ERR_NO_INTERFACE,
3874                        _("Could not find physical NIC with name '%s'"), name);
3875         goto cleanup;
3876     }
3877 
3878     result = 0;
3879 
3880  cleanup:
3881     esxVI_PhysicalNic_Free(&physicalNicList);
3882 
3883     return result;
3884 }
3885 
3886 
3887 
3888 int
esxVI_LookupPhysicalNicByMACAddress(esxVI_Context * ctx,const char * mac,esxVI_PhysicalNic ** physicalNic,esxVI_Occurrence occurrence)3889 esxVI_LookupPhysicalNicByMACAddress(esxVI_Context *ctx, const char *mac,
3890                                     esxVI_PhysicalNic **physicalNic,
3891                                     esxVI_Occurrence occurrence)
3892 {
3893     int result = -1;
3894     esxVI_PhysicalNic *physicalNicList = NULL;
3895     esxVI_PhysicalNic *candidate = NULL;
3896 
3897     ESX_VI_CHECK_ARG_LIST(physicalNic);
3898 
3899     if (esxVI_LookupPhysicalNicList(ctx, &physicalNicList) < 0)
3900         goto cleanup;
3901 
3902     /* Search for a matching physical NIC */
3903     for (candidate = physicalNicList; candidate;
3904          candidate = candidate->_next) {
3905         if (STRCASEEQ(candidate->mac, mac)) {
3906             if (esxVI_PhysicalNic_DeepCopy(physicalNic, candidate) < 0)
3907                 goto cleanup;
3908 
3909             /* Found physical NIC with matching MAC address */
3910             result = 0;
3911 
3912             goto cleanup;
3913         }
3914     }
3915 
3916     if (!(*physicalNic) && occurrence != esxVI_Occurrence_OptionalItem) {
3917         virReportError(VIR_ERR_NO_INTERFACE,
3918                        _("Could not find physical NIC with MAC address '%s'"), mac);
3919         goto cleanup;
3920     }
3921 
3922     result = 0;
3923 
3924  cleanup:
3925     esxVI_PhysicalNic_Free(&physicalNicList);
3926 
3927     return result;
3928 }
3929 
3930 
3931 
3932 int
esxVI_LookupHostVirtualSwitchList(esxVI_Context * ctx,esxVI_HostVirtualSwitch ** hostVirtualSwitchList)3933 esxVI_LookupHostVirtualSwitchList(esxVI_Context *ctx,
3934                                   esxVI_HostVirtualSwitch **hostVirtualSwitchList)
3935 {
3936     int result = -1;
3937     esxVI_String *propertyNameList = NULL;
3938     esxVI_ObjectContent *hostSystem = NULL;
3939     esxVI_DynamicProperty *dynamicProperty = NULL;
3940 
3941     ESX_VI_CHECK_ARG_LIST(hostVirtualSwitchList);
3942 
3943     if (esxVI_String_AppendValueToList(&propertyNameList,
3944                                        "config.network.vswitch") < 0 ||
3945         esxVI_LookupHostSystemProperties(ctx, propertyNameList,
3946                                          &hostSystem) < 0) {
3947         goto cleanup;
3948     }
3949 
3950     for (dynamicProperty = hostSystem->propSet; dynamicProperty;
3951          dynamicProperty = dynamicProperty->_next) {
3952         if (STREQ(dynamicProperty->name, "config.network.vswitch")) {
3953             if (esxVI_HostVirtualSwitch_CastListFromAnyType
3954                  (dynamicProperty->val, hostVirtualSwitchList) < 0) {
3955                 goto cleanup;
3956             }
3957         } else {
3958             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3959         }
3960     }
3961 
3962     result = 0;
3963 
3964  cleanup:
3965     esxVI_String_Free(&propertyNameList);
3966     esxVI_ObjectContent_Free(&hostSystem);
3967 
3968     return result;
3969 }
3970 
3971 
3972 
3973 int
esxVI_LookupHostVirtualSwitchByName(esxVI_Context * ctx,const char * name,esxVI_HostVirtualSwitch ** hostVirtualSwitch,esxVI_Occurrence occurrence)3974 esxVI_LookupHostVirtualSwitchByName(esxVI_Context *ctx, const char *name,
3975                                     esxVI_HostVirtualSwitch **hostVirtualSwitch,
3976                                     esxVI_Occurrence occurrence)
3977 {
3978     int result = -1;
3979     esxVI_HostVirtualSwitch *hostVirtualSwitchList = NULL;
3980     esxVI_HostVirtualSwitch *candidate = NULL;
3981 
3982     ESX_VI_CHECK_ARG_LIST(hostVirtualSwitch);
3983 
3984     if (esxVI_LookupHostVirtualSwitchList(ctx, &hostVirtualSwitchList) < 0)
3985         goto cleanup;
3986 
3987     /* Search for a matching HostVirtualSwitch */
3988     for (candidate = hostVirtualSwitchList; candidate;
3989          candidate = candidate->_next) {
3990         if (STREQ(candidate->name, name)) {
3991             if (esxVI_HostVirtualSwitch_DeepCopy(hostVirtualSwitch,
3992                                                  candidate) < 0) {
3993                 goto cleanup;
3994             }
3995 
3996             /* Found HostVirtualSwitch with matching name */
3997             result = 0;
3998 
3999             goto cleanup;
4000         }
4001     }
4002 
4003     if (!(*hostVirtualSwitch) &&
4004         occurrence != esxVI_Occurrence_OptionalItem) {
4005         virReportError(VIR_ERR_NO_NETWORK,
4006                        _("Could not find HostVirtualSwitch with name '%s'"),
4007                        name);
4008         goto cleanup;
4009     }
4010 
4011     result = 0;
4012 
4013  cleanup:
4014     esxVI_HostVirtualSwitch_Free(&hostVirtualSwitchList);
4015 
4016     return result;
4017 }
4018 
4019 
4020 
4021 int
esxVI_LookupHostPortGroupList(esxVI_Context * ctx,esxVI_HostPortGroup ** hostPortGroupList)4022 esxVI_LookupHostPortGroupList(esxVI_Context *ctx,
4023                               esxVI_HostPortGroup **hostPortGroupList)
4024 {
4025     int result = -1;
4026     esxVI_String *propertyNameList = NULL;
4027     esxVI_ObjectContent *hostSystem = NULL;
4028     esxVI_DynamicProperty *dynamicProperty = NULL;
4029 
4030     ESX_VI_CHECK_ARG_LIST(hostPortGroupList);
4031 
4032     if (esxVI_String_AppendValueToList(&propertyNameList,
4033                                        "config.network.portgroup") < 0 ||
4034         esxVI_LookupHostSystemProperties(ctx, propertyNameList,
4035                                          &hostSystem) < 0) {
4036         goto cleanup;
4037     }
4038 
4039     for (dynamicProperty = hostSystem->propSet; dynamicProperty;
4040          dynamicProperty = dynamicProperty->_next) {
4041         if (STREQ(dynamicProperty->name, "config.network.portgroup")) {
4042             if (esxVI_HostPortGroup_CastListFromAnyType
4043                   (dynamicProperty->val, hostPortGroupList) < 0) {
4044                 goto cleanup;
4045             }
4046 
4047             break;
4048         } else {
4049             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
4050         }
4051     }
4052 
4053     result = 0;
4054 
4055  cleanup:
4056     esxVI_String_Free(&propertyNameList);
4057     esxVI_ObjectContent_Free(&hostSystem);
4058 
4059     return result;
4060 }
4061 
4062 
4063 
4064 int
esxVI_LookupNetworkList(esxVI_Context * ctx,esxVI_String * propertyNameList,esxVI_ObjectContent ** networkList)4065 esxVI_LookupNetworkList(esxVI_Context *ctx, esxVI_String *propertyNameList,
4066                         esxVI_ObjectContent **networkList)
4067 {
4068     return esxVI_LookupObjectContentByType(ctx, ctx->datacenter->_reference,
4069                                            "Network", propertyNameList,
4070                                            networkList,
4071                                            esxVI_Occurrence_OptionalList);
4072 }
4073 
4074 
4075 
4076 int
esxVI_HandleVirtualMachineQuestion(esxVI_Context * ctx,esxVI_ManagedObjectReference * virtualMachine,esxVI_VirtualMachineQuestionInfo * questionInfo,bool autoAnswer,bool * blocked)4077 esxVI_HandleVirtualMachineQuestion
4078   (esxVI_Context *ctx, esxVI_ManagedObjectReference *virtualMachine,
4079    esxVI_VirtualMachineQuestionInfo *questionInfo, bool autoAnswer,
4080    bool *blocked)
4081 {
4082     esxVI_ElementDescription *elementDescription = NULL;
4083     g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
4084     esxVI_ElementDescription *answerChoice = NULL;
4085     int answerIndex = 0;
4086     g_autofree char *possibleAnswers = NULL;
4087 
4088     if (!blocked) {
4089         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
4090         return -1;
4091     }
4092 
4093     *blocked = false;
4094 
4095     if (questionInfo->choice->choiceInfo) {
4096         for (elementDescription = questionInfo->choice->choiceInfo;
4097              elementDescription;
4098              elementDescription = elementDescription->_next) {
4099             virBufferAsprintf(&buffer, "'%s'", elementDescription->label);
4100 
4101             if (elementDescription->_next)
4102                 virBufferAddLit(&buffer, ", ");
4103 
4104             if (!answerChoice &&
4105                 questionInfo->choice->defaultIndex &&
4106                 questionInfo->choice->defaultIndex->value == answerIndex) {
4107                 answerChoice = elementDescription;
4108             }
4109 
4110             ++answerIndex;
4111         }
4112 
4113         possibleAnswers = virBufferContentAndReset(&buffer);
4114     }
4115 
4116     if (autoAnswer) {
4117         if (!possibleAnswers) {
4118             virReportError(VIR_ERR_INTERNAL_ERROR,
4119                            _("Pending question blocks virtual machine execution, "
4120                              "question is '%s', no possible answers"),
4121                            questionInfo->text);
4122 
4123             *blocked = true;
4124             return -1;
4125         } else if (!answerChoice) {
4126             virReportError(VIR_ERR_INTERNAL_ERROR,
4127                            _("Pending question blocks virtual machine execution, "
4128                              "question is '%s', possible answers are %s, but no "
4129                              "default answer is specified"), questionInfo->text,
4130                            possibleAnswers);
4131 
4132             *blocked = true;
4133             return -1;
4134         }
4135 
4136         VIR_INFO("Pending question blocks virtual machine execution, "
4137                  "question is '%s', possible answers are %s, responding "
4138                  "with default answer '%s'", questionInfo->text,
4139                  possibleAnswers, answerChoice->label);
4140 
4141         if (esxVI_AnswerVM(ctx, virtualMachine, questionInfo->id,
4142                            answerChoice->key) < 0) {
4143             return -1;
4144         }
4145     } else {
4146         if (possibleAnswers) {
4147             virReportError(VIR_ERR_INTERNAL_ERROR,
4148                            _("Pending question blocks virtual machine execution, "
4149                              "question is '%s', possible answers are %s"),
4150                            questionInfo->text, possibleAnswers);
4151         } else {
4152             virReportError(VIR_ERR_INTERNAL_ERROR,
4153                            _("Pending question blocks virtual machine execution, "
4154                              "question is '%s', no possible answers"),
4155                            questionInfo->text);
4156         }
4157 
4158         *blocked = true;
4159         return -1;
4160     }
4161 
4162     return 0;
4163 
4164 }
4165 
4166 
4167 
4168 int
esxVI_WaitForTaskCompletion(esxVI_Context * ctx,esxVI_ManagedObjectReference * task,const unsigned char * virtualMachineUuid,esxVI_Occurrence virtualMachineOccurrence,bool autoAnswer,esxVI_TaskInfoState * finalState,char ** errorMessage)4169 esxVI_WaitForTaskCompletion(esxVI_Context *ctx,
4170                             esxVI_ManagedObjectReference *task,
4171                             const unsigned char *virtualMachineUuid,
4172                             esxVI_Occurrence virtualMachineOccurrence,
4173                             bool autoAnswer, esxVI_TaskInfoState *finalState,
4174                             char **errorMessage)
4175 {
4176     int result = -1;
4177     esxVI_ObjectSpec *objectSpec = NULL;
4178     bool objectSpec_isAppended = false;
4179     esxVI_PropertySpec *propertySpec = NULL;
4180     bool propertySpec_isAppended = false;
4181     esxVI_PropertyFilterSpec *propertyFilterSpec = NULL;
4182     esxVI_ManagedObjectReference *propertyFilter = NULL;
4183     char *version = NULL;
4184     esxVI_UpdateSet *updateSet = NULL;
4185     esxVI_PropertyFilterUpdate *propertyFilterUpdate = NULL;
4186     esxVI_ObjectUpdate *objectUpdate = NULL;
4187     esxVI_PropertyChange *propertyChange = NULL;
4188     esxVI_AnyType *propertyValue = NULL;
4189     esxVI_TaskInfoState state = esxVI_TaskInfoState_Undefined;
4190     bool blocked;
4191     esxVI_TaskInfo *taskInfo = NULL;
4192 
4193     ESX_VI_CHECK_ARG_LIST(errorMessage);
4194 
4195     version = g_strdup("");
4196 
4197     if (esxVI_ObjectSpec_Alloc(&objectSpec) < 0)
4198         goto cleanup;
4199 
4200     objectSpec->obj = task;
4201     objectSpec->skip = esxVI_Boolean_False;
4202 
4203     if (esxVI_PropertySpec_Alloc(&propertySpec) < 0)
4204         goto cleanup;
4205 
4206     propertySpec->type = task->type;
4207 
4208     if (esxVI_String_AppendValueToList(&propertySpec->pathSet,
4209                                        "info.state") < 0 ||
4210         esxVI_PropertyFilterSpec_Alloc(&propertyFilterSpec) < 0 ||
4211         esxVI_PropertySpec_AppendToList(&propertyFilterSpec->propSet,
4212                                         propertySpec) < 0) {
4213         goto cleanup;
4214     }
4215 
4216     propertySpec_isAppended = true;
4217 
4218     if (esxVI_ObjectSpec_AppendToList(&propertyFilterSpec->objectSet,
4219                                       objectSpec) < 0) {
4220         goto cleanup;
4221     }
4222 
4223     objectSpec_isAppended = true;
4224 
4225     if (esxVI_CreateFilter(ctx, propertyFilterSpec, esxVI_Boolean_True,
4226                            &propertyFilter) < 0) {
4227         goto cleanup;
4228     }
4229 
4230     while (state != esxVI_TaskInfoState_Success &&
4231            state != esxVI_TaskInfoState_Error) {
4232         esxVI_UpdateSet_Free(&updateSet);
4233 
4234         if (virtualMachineUuid) {
4235             if (esxVI_LookupAndHandleVirtualMachineQuestion
4236                   (ctx, virtualMachineUuid, virtualMachineOccurrence,
4237                    autoAnswer, &blocked) < 0) {
4238                 /*
4239                  * FIXME: Disable error reporting here, so possible errors from
4240                  *        esxVI_LookupTaskInfoByTask() and esxVI_CancelTask()
4241                  *        don't overwrite the actual error
4242                  */
4243                 if (esxVI_LookupTaskInfoByTask(ctx, task, &taskInfo))
4244                     goto cleanup;
4245 
4246                 if (taskInfo->cancelable == esxVI_Boolean_True) {
4247                     if (esxVI_CancelTask(ctx, task) < 0 && blocked) {
4248                         VIR_ERROR(_("Cancelable task is blocked by an "
4249                                      "unanswered question but cancellation "
4250                                      "failed"));
4251                     }
4252                 } else if (blocked) {
4253                     VIR_ERROR(_("Non-cancelable task is blocked by an "
4254                                  "unanswered question"));
4255                 }
4256 
4257                 /* FIXME: Enable error reporting here again */
4258 
4259                 goto cleanup;
4260             }
4261         }
4262 
4263         if (esxVI_WaitForUpdates(ctx, version, &updateSet) < 0)
4264             goto cleanup;
4265 
4266         g_free(version);
4267         version = g_strdup(updateSet->version);
4268 
4269         if (!updateSet->filterSet)
4270             continue;
4271 
4272         for (propertyFilterUpdate = updateSet->filterSet;
4273              propertyFilterUpdate;
4274              propertyFilterUpdate = propertyFilterUpdate->_next) {
4275             for (objectUpdate = propertyFilterUpdate->objectSet;
4276                  objectUpdate; objectUpdate = objectUpdate->_next) {
4277                 for (propertyChange = objectUpdate->changeSet;
4278                      propertyChange;
4279                      propertyChange = propertyChange->_next) {
4280                     if (STREQ(propertyChange->name, "info.state")) {
4281                         if (propertyChange->op == esxVI_PropertyChangeOp_Add ||
4282                             propertyChange->op == esxVI_PropertyChangeOp_Assign) {
4283                             propertyValue = propertyChange->val;
4284                         } else {
4285                             propertyValue = NULL;
4286                         }
4287                     }
4288                 }
4289             }
4290         }
4291 
4292         if (!propertyValue)
4293             continue;
4294 
4295         if (esxVI_TaskInfoState_CastFromAnyType(propertyValue, &state) < 0)
4296             goto cleanup;
4297     }
4298 
4299     if (esxVI_DestroyPropertyFilter(ctx, propertyFilter) < 0)
4300         VIR_DEBUG("DestroyPropertyFilter failed");
4301 
4302     if (esxVI_TaskInfoState_CastFromAnyType(propertyValue, finalState) < 0)
4303         goto cleanup;
4304 
4305     if (*finalState != esxVI_TaskInfoState_Success) {
4306         if (esxVI_LookupTaskInfoByTask(ctx, task, &taskInfo))
4307             goto cleanup;
4308 
4309         if (!taskInfo->error) {
4310             *errorMessage = g_strdup(_("Unknown error"));
4311         } else if (!taskInfo->error->localizedMessage) {
4312             *errorMessage = g_strdup(taskInfo->error->fault->_actualType);
4313         } else {
4314             *errorMessage = g_strdup_printf("%s - %s",
4315                                             taskInfo->error->fault->_actualType,
4316                                             taskInfo->error->localizedMessage);
4317         }
4318     }
4319 
4320     result = 0;
4321 
4322  cleanup:
4323     /*
4324      * Remove values given by the caller from the data structures to prevent
4325      * them from being freed by the call to esxVI_PropertyFilterSpec_Free().
4326      */
4327     if (objectSpec)
4328         objectSpec->obj = NULL;
4329 
4330     if (propertySpec)
4331         propertySpec->type = NULL;
4332 
4333     if (!objectSpec_isAppended)
4334         esxVI_ObjectSpec_Free(&objectSpec);
4335 
4336     if (!propertySpec_isAppended)
4337         esxVI_PropertySpec_Free(&propertySpec);
4338 
4339     esxVI_PropertyFilterSpec_Free(&propertyFilterSpec);
4340     esxVI_ManagedObjectReference_Free(&propertyFilter);
4341     g_free(version);
4342     esxVI_UpdateSet_Free(&updateSet);
4343     esxVI_TaskInfo_Free(&taskInfo);
4344 
4345     return result;
4346 }
4347 
4348 
4349 
4350 int
esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo * parsedHostCpuIdInfo,esxVI_HostCpuIdInfo * hostCpuIdInfo)4351 esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedHostCpuIdInfo,
4352                          esxVI_HostCpuIdInfo *hostCpuIdInfo)
4353 {
4354     int expectedLength = 39; /* = strlen("----:----:----:----:----:----:----:----"); */
4355     char *input[4] = { hostCpuIdInfo->eax, hostCpuIdInfo->ebx,
4356                        hostCpuIdInfo->ecx, hostCpuIdInfo->edx };
4357     char *output[4] = { parsedHostCpuIdInfo->eax, parsedHostCpuIdInfo->ebx,
4358                         parsedHostCpuIdInfo->ecx, parsedHostCpuIdInfo->edx };
4359     const char *name[4] = { "eax", "ebx", "ecx", "edx" };
4360     size_t r, i, o;
4361 
4362     memset(parsedHostCpuIdInfo, 0, sizeof(*parsedHostCpuIdInfo));
4363 
4364     parsedHostCpuIdInfo->level = hostCpuIdInfo->level->value;
4365 
4366     for (r = 0; r < 4; ++r) {
4367         if (strlen(input[r]) != expectedLength) {
4368             virReportError(VIR_ERR_INTERNAL_ERROR,
4369                            _("HostCpuIdInfo register '%s' has an unexpected length"),
4370                            name[r]);
4371             return -1;
4372         }
4373 
4374         /* Strip the ':' and invert the "bit" order from 31..0 to 0..31 */
4375         for (i = 0, o = 31; i < expectedLength; i += 5, o -= 4) {
4376             output[r][o] = input[r][i];
4377             output[r][o - 1] = input[r][i + 1];
4378             output[r][o - 2] = input[r][i + 2];
4379             output[r][o - 3] = input[r][i + 3];
4380 
4381             if (i + 4 < expectedLength && input[r][i + 4] != ':') {
4382                 virReportError(VIR_ERR_INTERNAL_ERROR,
4383                                _("HostCpuIdInfo register '%s' has an unexpected format"),
4384                                name[r]);
4385                 return -1;
4386             }
4387         }
4388     }
4389 
4390     return 0;
4391 }
4392 
4393 
4394 
4395 const char *
esxVI_ProductLineToDisplayName(esxVI_ProductLine productLine)4396 esxVI_ProductLineToDisplayName(esxVI_ProductLine productLine)
4397 {
4398     switch (productLine) {
4399       case esxVI_ProductLine_GSX:
4400         return "Server/GSX";
4401 
4402       case esxVI_ProductLine_ESX:
4403         return "ESX(i)";
4404 
4405       case esxVI_ProductLine_VPX:
4406         return "vCenter/VPX";
4407 
4408       default:
4409         return "<unknown>";
4410     }
4411 }
4412 
4413 
4414 
4415 int
esxVI_ProductVersionToDefaultVirtualHWVersion(esxVI_ProductLine productLine,unsigned long productVersion)4416 esxVI_ProductVersionToDefaultVirtualHWVersion(esxVI_ProductLine productLine,
4417                                               unsigned long productVersion)
4418 {
4419     /* product version == 1000000 * major + 1000 * minor + micro */
4420     int major = productVersion / 1000000;
4421     int minor = productVersion / 1000 - major * 1000;
4422 
4423     /*
4424      * virtualHW.version compatibility matrix:
4425      *
4426      *              4 7 8 9 10   API
4427      *   ESX 3.5    +            2.5
4428      *   ESX 4.0    + +          4.0
4429      *   ESX 4.1    + +          4.1
4430      *   ESX 5.0    + + +        5.0
4431      *   ESX 5.1    + + + +      5.1
4432      *   ESX 5.5    + + + + +    5.5
4433      *   ESX 6.0    + + + + +    6.0
4434      *   GSX 2.0    + +          2.5
4435      */
4436     switch (productLine) {
4437       case esxVI_ProductLine_GSX:
4438         return 7;
4439 
4440       case esxVI_ProductLine_ESX:
4441         switch (major) {
4442           case 3:
4443             return 4;
4444 
4445           case 4:
4446             return 7;
4447 
4448           case 5:
4449             if (minor < 5)
4450                 return 9;
4451 
4452             return 10;
4453 
4454           case 6:
4455             return 10;
4456 
4457           default:
4458             return 8;
4459         }
4460 
4461       case esxVI_ProductLine_VPX:
4462         switch (major) {
4463           case 2:
4464             return 4;
4465 
4466           case 4:
4467             return 7;
4468 
4469           case 5:
4470             if (minor < 5)
4471                 return 9;
4472 
4473             return 10;
4474 
4475           case 6:
4476             return 10;
4477 
4478           default:
4479             return 8;
4480         }
4481 
4482       default:
4483         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4484                        _("Unexpected product line"));
4485         return -1;
4486     }
4487 }
4488 
4489 
4490 
4491 int
esxVI_LookupHostInternetScsiHbaStaticTargetByName(esxVI_Context * ctx,const char * name,esxVI_HostInternetScsiHbaStaticTarget ** target,esxVI_Occurrence occurrence)4492 esxVI_LookupHostInternetScsiHbaStaticTargetByName
4493   (esxVI_Context *ctx, const char *name,
4494    esxVI_HostInternetScsiHbaStaticTarget **target, esxVI_Occurrence occurrence)
4495 {
4496     int result = -1;
4497     esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
4498     esxVI_HostInternetScsiHbaStaticTarget *candidate = NULL;
4499 
4500     if (esxVI_LookupHostInternetScsiHba(ctx, &hostInternetScsiHba) < 0) {
4501         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4502                        _("Unable to obtain hostInternetScsiHba"));
4503         goto cleanup;
4504     }
4505 
4506     if (!hostInternetScsiHba) {
4507         /* iSCSI adapter may not be enabled for this host */
4508         return 0;
4509     }
4510 
4511     for (candidate = hostInternetScsiHba->configuredStaticTarget;
4512          candidate; candidate = candidate->_next) {
4513         if (STREQ(candidate->iScsiName, name))
4514             break;
4515     }
4516 
4517     if (!candidate) {
4518         if (occurrence == esxVI_Occurrence_RequiredItem) {
4519             virReportError(VIR_ERR_NO_STORAGE_POOL,
4520                            _("Could not find storage pool with name: %s"), name);
4521         }
4522 
4523         goto cleanup;
4524     }
4525 
4526     if (esxVI_HostInternetScsiHbaStaticTarget_DeepCopy(target, candidate) < 0)
4527         goto cleanup;
4528 
4529     result = 0;
4530 
4531  cleanup:
4532     esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
4533 
4534     return result;
4535 }
4536 
4537 
4538 
4539 int
esxVI_LookupHostInternetScsiHba(esxVI_Context * ctx,esxVI_HostInternetScsiHba ** hostInternetScsiHba)4540 esxVI_LookupHostInternetScsiHba(esxVI_Context *ctx,
4541                                 esxVI_HostInternetScsiHba **hostInternetScsiHba)
4542 {
4543     int result = -1;
4544     esxVI_DynamicProperty *dynamicProperty = NULL;
4545     esxVI_ObjectContent *hostSystem = NULL;
4546     esxVI_String *propertyNameList = NULL;
4547     esxVI_HostHostBusAdapter *hostHostBusAdapterList = NULL;
4548     esxVI_HostHostBusAdapter *hostHostBusAdapter = NULL;
4549 
4550     if (esxVI_String_AppendValueToList
4551           (&propertyNameList, "config.storageDevice.hostBusAdapter") < 0 ||
4552         esxVI_LookupHostSystemProperties(ctx, propertyNameList,
4553                                          &hostSystem) < 0) {
4554         goto cleanup;
4555     }
4556 
4557     for (dynamicProperty = hostSystem->propSet; dynamicProperty;
4558          dynamicProperty = dynamicProperty->_next) {
4559         if (STREQ(dynamicProperty->name,
4560                   "config.storageDevice.hostBusAdapter")) {
4561             if (esxVI_HostHostBusAdapter_CastListFromAnyType
4562                 (dynamicProperty->val, &hostHostBusAdapterList) < 0 ||
4563                 !hostHostBusAdapterList) {
4564                 goto cleanup;
4565             }
4566         } else {
4567             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
4568         }
4569     }
4570 
4571     /* See vSphere API documentation about HostInternetScsiHba for details */
4572     for (hostHostBusAdapter = hostHostBusAdapterList;
4573          hostHostBusAdapter;
4574          hostHostBusAdapter = hostHostBusAdapter->_next) {
4575         esxVI_HostInternetScsiHba *candidate =
4576             esxVI_HostInternetScsiHba_DynamicCast(hostHostBusAdapter);
4577 
4578         if (candidate) {
4579             if (esxVI_HostInternetScsiHba_DeepCopy(hostInternetScsiHba,
4580                   candidate) < 0) {
4581                 goto cleanup;
4582             }
4583             break;
4584         }
4585     }
4586 
4587     result = 0;
4588 
4589  cleanup:
4590     esxVI_String_Free(&propertyNameList);
4591     esxVI_ObjectContent_Free(&hostSystem);
4592     esxVI_HostHostBusAdapter_Free(&hostHostBusAdapterList);
4593 
4594     return result;
4595 }
4596 
4597 
4598 
4599 int
esxVI_LookupScsiLunList(esxVI_Context * ctx,esxVI_ScsiLun ** scsiLunList)4600 esxVI_LookupScsiLunList(esxVI_Context *ctx, esxVI_ScsiLun **scsiLunList)
4601 {
4602     int result = -1;
4603     esxVI_String *propertyNameList = NULL;
4604     esxVI_ObjectContent *hostSystem = NULL;
4605     esxVI_DynamicProperty *dynamicProperty;
4606 
4607     if (esxVI_String_AppendValueToList(&propertyNameList,
4608                                        "config.storageDevice.scsiLun") < 0 ||
4609         esxVI_LookupHostSystemProperties(ctx, propertyNameList,
4610                                          &hostSystem) < 0) {
4611         goto cleanup;
4612     }
4613 
4614     for (dynamicProperty = hostSystem->propSet; dynamicProperty;
4615          dynamicProperty = dynamicProperty->_next) {
4616         if (STREQ(dynamicProperty->name, "config.storageDevice.scsiLun")) {
4617             if (esxVI_ScsiLun_CastListFromAnyType(dynamicProperty->val,
4618                                                   scsiLunList) < 0) {
4619                 goto cleanup;
4620             }
4621 
4622             break;
4623         } else {
4624             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
4625         }
4626     }
4627 
4628     result = 0;
4629 
4630  cleanup:
4631     esxVI_String_Free(&propertyNameList);
4632     esxVI_ObjectContent_Free(&hostSystem);
4633 
4634     return result;
4635 }
4636 
4637 
4638 
4639 int
esxVI_LookupHostScsiTopologyLunListByTargetName(esxVI_Context * ctx,const char * name,esxVI_HostScsiTopologyLun ** hostScsiTopologyLunList)4640 esxVI_LookupHostScsiTopologyLunListByTargetName
4641   (esxVI_Context *ctx, const char *name,
4642    esxVI_HostScsiTopologyLun **hostScsiTopologyLunList)
4643 {
4644     int result = -1;
4645     esxVI_DynamicProperty *dynamicProperty = NULL;
4646     esxVI_ObjectContent *hostSystem = NULL;
4647     esxVI_String *propertyNameList = NULL;
4648     esxVI_HostScsiTopologyInterface *hostScsiInterfaceList = NULL;
4649     esxVI_HostScsiTopologyInterface *hostScsiInterface = NULL;
4650     esxVI_HostScsiTopologyTarget *hostScsiTopologyTarget = NULL;
4651     bool found = false;
4652     esxVI_HostInternetScsiTargetTransport *candidate = NULL;
4653 
4654     ESX_VI_CHECK_ARG_LIST(hostScsiTopologyLunList);
4655 
4656     if (esxVI_String_AppendValueToList
4657           (&propertyNameList,
4658            "config.storageDevice.scsiTopology.adapter") < 0 ||
4659         esxVI_LookupHostSystemProperties(ctx, propertyNameList,
4660                                          &hostSystem) < 0) {
4661         goto cleanup;
4662     }
4663 
4664     for (dynamicProperty = hostSystem->propSet; dynamicProperty;
4665          dynamicProperty = dynamicProperty->_next) {
4666         if (STREQ(dynamicProperty->name,
4667                   "config.storageDevice.scsiTopology.adapter")) {
4668             esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
4669 
4670             if (esxVI_HostScsiTopologyInterface_CastListFromAnyType
4671                   (dynamicProperty->val, &hostScsiInterfaceList) < 0) {
4672                 goto cleanup;
4673             }
4674 
4675             break;
4676         } else {
4677             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
4678         }
4679     }
4680 
4681     if (hostScsiInterfaceList == NULL) {
4682         /* iSCSI adapter may not be enabled */
4683         return 0;
4684     }
4685 
4686     /* See vSphere API documentation about HostScsiTopologyInterface */
4687     for (hostScsiInterface = hostScsiInterfaceList;
4688          hostScsiInterface && !found;
4689          hostScsiInterface = hostScsiInterface->_next) {
4690         for (hostScsiTopologyTarget = hostScsiInterface->target;
4691              hostScsiTopologyTarget;
4692              hostScsiTopologyTarget = hostScsiTopologyTarget->_next) {
4693             candidate = esxVI_HostInternetScsiTargetTransport_DynamicCast
4694                           (hostScsiTopologyTarget->transport);
4695 
4696             if (candidate && STREQ(candidate->iScsiName, name)) {
4697                 found = true;
4698                 break;
4699             }
4700         }
4701     }
4702 
4703     if (!found || !hostScsiTopologyTarget)
4704         goto cleanup;
4705 
4706     if (!hostScsiTopologyTarget->lun) {
4707         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4708                        _("Target not found"));
4709         goto cleanup;
4710     }
4711 
4712     if (esxVI_HostScsiTopologyLun_DeepCopyList(hostScsiTopologyLunList,
4713                                                hostScsiTopologyTarget->lun) < 0) {
4714         goto cleanup;
4715     }
4716 
4717     result = 0;
4718 
4719  cleanup:
4720     esxVI_String_Free(&propertyNameList);
4721     esxVI_ObjectContent_Free(&hostSystem);
4722     esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
4723 
4724     return result;
4725 }
4726 
4727 
4728 
4729 int
esxVI_LookupStoragePoolNameByScsiLunKey(esxVI_Context * ctx,const char * key,char ** poolName)4730 esxVI_LookupStoragePoolNameByScsiLunKey(esxVI_Context *ctx,
4731                                         const char *key,
4732                                         char **poolName)
4733 {
4734     int result = -1;
4735     esxVI_DynamicProperty *dynamicProperty = NULL;
4736     esxVI_ObjectContent *hostSystem = NULL;
4737     esxVI_String *propertyNameList = NULL;
4738     esxVI_HostScsiTopologyInterface *hostScsiInterfaceList = NULL;
4739     esxVI_HostScsiTopologyInterface *hostScsiInterface = NULL;
4740     esxVI_HostScsiTopologyTarget *hostScsiTopologyTarget = NULL;
4741     esxVI_HostInternetScsiTargetTransport *candidate;
4742     esxVI_HostScsiTopologyLun *hostScsiTopologyLun;
4743     bool found = false;
4744 
4745     ESX_VI_CHECK_ARG_LIST(poolName);
4746 
4747     if (esxVI_String_AppendValueToList
4748           (&propertyNameList,
4749            "config.storageDevice.scsiTopology.adapter") < 0 ||
4750         esxVI_LookupHostSystemProperties(ctx, propertyNameList,
4751                                          &hostSystem) < 0) {
4752         goto cleanup;
4753     }
4754 
4755     for (dynamicProperty = hostSystem->propSet; dynamicProperty;
4756          dynamicProperty = dynamicProperty->_next) {
4757         if (STREQ(dynamicProperty->name,
4758                   "config.storageDevice.scsiTopology.adapter")) {
4759             esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
4760 
4761             if (esxVI_HostScsiTopologyInterface_CastListFromAnyType
4762                   (dynamicProperty->val, &hostScsiInterfaceList) < 0) {
4763                 goto cleanup;
4764             }
4765 
4766             break;
4767         } else {
4768             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
4769         }
4770     }
4771 
4772     if (!hostScsiInterfaceList) {
4773         /* iSCSI adapter may not be enabled */
4774         return 0;
4775     }
4776 
4777     /* See vSphere API documentation about HostScsiTopologyInterface */
4778     for (hostScsiInterface = hostScsiInterfaceList;
4779          hostScsiInterface && !found;
4780          hostScsiInterface = hostScsiInterface->_next) {
4781         for (hostScsiTopologyTarget = hostScsiInterface->target;
4782              hostScsiTopologyTarget;
4783              hostScsiTopologyTarget = hostScsiTopologyTarget->_next) {
4784             candidate = esxVI_HostInternetScsiTargetTransport_DynamicCast
4785                 (hostScsiTopologyTarget->transport);
4786 
4787             if (candidate) {
4788                 /* iterate hostScsiTopologyLun list to find matching key */
4789                 for (hostScsiTopologyLun = hostScsiTopologyTarget->lun;
4790                      hostScsiTopologyLun;
4791                      hostScsiTopologyLun = hostScsiTopologyLun->_next) {
4792                     if (STREQ(hostScsiTopologyLun->scsiLun, key))
4793                         *poolName = g_strdup(candidate->iScsiName);
4794                 }
4795 
4796                 /* hostScsiTopologyLun iteration done, terminate loop */
4797                 break;
4798             }
4799         }
4800     }
4801 
4802     result = 0;
4803 
4804  cleanup:
4805     esxVI_ObjectContent_Free(&hostSystem);
4806     esxVI_String_Free(&propertyNameList);
4807     esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
4808 
4809     return result;
4810 }
4811 
4812 
4813 
4814 #define ESX_VI__TEMPLATE__PROPERTY__CAST_FROM_ANY_TYPE_IGNORE(_name) \
4815     if (STREQ(dynamicProperty->name, #_name)) { \
4816         continue; \
4817     }
4818 
4819 
4820 
4821 #define ESX_VI__TEMPLATE__PROPERTY__CAST_FROM_ANY_TYPE(_type, _name) \
4822     if (STREQ(dynamicProperty->name, #_name)) { \
4823         if (esxVI_##_type##_CastFromAnyType(dynamicProperty->val, \
4824                                             &(*ptrptr)->_name) < 0) { \
4825             goto cleanup; \
4826         } \
4827  \
4828         continue; \
4829     }
4830 
4831 
4832 
4833 #define ESX_VI__TEMPLATE__PROPERTY__CAST_LIST_FROM_ANY_TYPE(_type, _name) \
4834     if (STREQ(dynamicProperty->name, #_name)) { \
4835         if (esxVI_##_type##_CastListFromAnyType(dynamicProperty->val, \
4836                                                 &(*ptrptr)->_name) < 0) { \
4837             goto cleanup; \
4838         } \
4839  \
4840         continue; \
4841     }
4842 
4843 
4844 
4845 #define ESX_VI__TEMPLATE__PROPERTY__CAST_VALUE_FROM_ANY_TYPE(_type, _name) \
4846     if (STREQ(dynamicProperty->name, #_name)) { \
4847         if (esxVI_##_type##_CastValueFromAnyType(dynamicProperty->val, \
4848                                                  &(*ptrptr)->_name) < 0) { \
4849             goto cleanup; \
4850         } \
4851  \
4852         continue; \
4853     }
4854 
4855 
4856 
4857 #define ESX_VI__TEMPLATE__LOOKUP(_type, _complete_properties, \
4858                                  _cast_from_anytype) \
4859     int \
4860     esxVI_Lookup##_type(esxVI_Context *ctx, const char* name /* optional */, \
4861                         esxVI_ManagedObjectReference *root, \
4862                         esxVI_String *selectedPropertyNameList /* optional */,\
4863                         esxVI_##_type **ptrptr, esxVI_Occurrence occurrence) \
4864     { \
4865         int result = -1; \
4866         const char *completePropertyNameValueList = _complete_properties; \
4867         esxVI_String *propertyNameList = NULL; \
4868         esxVI_ObjectContent *objectContent = NULL; \
4869         esxVI_ObjectContent *objectContentList = NULL; \
4870         esxVI_DynamicProperty *dynamicProperty = NULL; \
4871  \
4872         if (!ptrptr || *ptrptr) { \
4873             virReportError(VIR_ERR_INTERNAL_ERROR, "%s", \
4874                            _("Invalid argument")); \
4875             return -1; \
4876         } \
4877  \
4878         propertyNameList = selectedPropertyNameList; \
4879  \
4880         if (!propertyNameList && \
4881             esxVI_String_AppendValueListToList \
4882               (&propertyNameList, completePropertyNameValueList) < 0) { \
4883             goto cleanup; \
4884         } \
4885  \
4886         if (esxVI_LookupManagedObjectHelper(ctx, name, root, #_type, \
4887                                             propertyNameList, &objectContent, \
4888                                             &objectContentList, \
4889                                             occurrence) < 0) { \
4890             goto cleanup; \
4891         } \
4892  \
4893         if (!objectContent) { \
4894             /* not found, exit early */ \
4895             result = 0; \
4896             goto cleanup; \
4897         } \
4898  \
4899         if (esxVI_##_type##_Alloc(ptrptr) < 0) { \
4900             goto cleanup; \
4901         } \
4902  \
4903         if (esxVI_ManagedObjectReference_DeepCopy(&(*ptrptr)->_reference, \
4904                                                   objectContent->obj) < 0) { \
4905             goto cleanup; \
4906         } \
4907  \
4908         for (dynamicProperty = objectContent->propSet; \
4909              dynamicProperty; \
4910              dynamicProperty = dynamicProperty->_next) { \
4911             _cast_from_anytype \
4912  \
4913             VIR_WARN("Unexpected '%s' property", dynamicProperty->name); \
4914         } \
4915  \
4916         if (esxVI_##_type##_Validate(*ptrptr, selectedPropertyNameList) < 0) {\
4917             goto cleanup; \
4918         } \
4919  \
4920         result = 0; \
4921  \
4922       cleanup: \
4923         if (result < 0) { \
4924             esxVI_##_type##_Free(ptrptr); \
4925         } \
4926  \
4927         if (propertyNameList != selectedPropertyNameList) { \
4928             esxVI_String_Free(&propertyNameList); \
4929         } \
4930  \
4931         esxVI_ObjectContent_Free(&objectContentList); \
4932  \
4933         return result; \
4934     }
4935 
4936 
4937 
4938 static int
esxVI_LookupManagedObjectHelper(esxVI_Context * ctx,const char * name,esxVI_ManagedObjectReference * root,const char * type,esxVI_String * propertyNameList,esxVI_ObjectContent ** objectContent,esxVI_ObjectContent ** objectContentList,esxVI_Occurrence occurrence)4939 esxVI_LookupManagedObjectHelper(esxVI_Context *ctx,
4940                                 const char *name /* optional */,
4941                                 esxVI_ManagedObjectReference *root,
4942                                 const char *type,
4943                                 esxVI_String *propertyNameList,
4944                                 esxVI_ObjectContent **objectContent,
4945                                 esxVI_ObjectContent **objectContentList,
4946                                 esxVI_Occurrence occurrence)
4947 {
4948     int result = -1;
4949     esxVI_ObjectContent *candidate = NULL;
4950     char *name_candidate;
4951 
4952     if (!objectContent || *objectContent ||
4953         !objectContentList || *objectContentList) {
4954         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
4955         return -1;
4956     }
4957 
4958     if (!esxVI_String_ListContainsValue(propertyNameList, "name")) {
4959         virReportError(VIR_ERR_INTERNAL_ERROR,
4960                        _("Missing 'name' property in %s lookup"), type);
4961         goto cleanup;
4962     }
4963 
4964     if (esxVI_LookupObjectContentByType(ctx, root, type, propertyNameList,
4965                                         objectContentList,
4966                                         esxVI_Occurrence_OptionalList) < 0) {
4967         goto cleanup;
4968     }
4969 
4970     /* Search for a matching item */
4971     if (name) {
4972         for (candidate = *objectContentList; candidate;
4973              candidate = candidate->_next) {
4974             name_candidate = NULL;
4975 
4976             if (esxVI_GetStringValue(candidate, "name", &name_candidate,
4977                                      esxVI_Occurrence_RequiredItem) < 0) {
4978                 goto cleanup;
4979             }
4980 
4981             if (STREQ(name_candidate, name)) {
4982                 /* Found item with matching name */
4983                 break;
4984             }
4985         }
4986     } else {
4987         candidate = *objectContentList;
4988     }
4989 
4990     if (!candidate) {
4991         if (occurrence != esxVI_Occurrence_OptionalItem) {
4992             if (name) {
4993                 virReportError(VIR_ERR_INTERNAL_ERROR,
4994                                _("Could not find %s with name '%s'"), type, name);
4995             } else {
4996                 virReportError(VIR_ERR_INTERNAL_ERROR,
4997                                _("Could not find %s"), type);
4998             }
4999 
5000             goto cleanup;
5001         }
5002 
5003         result = 0;
5004 
5005         goto cleanup;
5006     }
5007 
5008     result = 0;
5009 
5010  cleanup:
5011     if (result < 0) {
5012         esxVI_ObjectContent_Free(objectContentList);
5013     } else {
5014         *objectContent = candidate;
5015     }
5016 
5017     return result;
5018 }
5019 
5020 
5021 
5022 #include "esx_vi.generated.c"
5023