1 /*
2  * vz_sdk.c: core driver functions for managing
3  * Parallels Cloud Server hosts
4  *
5  * Copyright (C) 2014 Parallels, Inc.
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 #include <stdarg.h>
25 
26 #include "virerror.h"
27 #include "viralloc.h"
28 #include "virstring.h"
29 #include "virlog.h"
30 #include "datatypes.h"
31 #include "domain_conf.h"
32 #include "storage_conf.h"
33 #include "virtime.h"
34 #include "virhostcpu.h"
35 #include "virsocketaddr.h"
36 #include "virutil.h"
37 
38 #include "vz_sdk.h"
39 
40 #define VIR_FROM_THIS VIR_FROM_PARALLELS
41 #define JOB_INFINIT_WAIT_TIMEOUT UINT_MAX
42 
43 static int
44 prlsdkUUIDParse(const char *uuidstr, unsigned char *uuid);
45 static void
46 prlsdkConvertError(PRL_RESULT pret);
47 static PRL_RESULT
48 prlsdkEventsHandler(PRL_HANDLE prlEvent, PRL_VOID_PTR opaque);
49 
50 VIR_LOG_INIT("parallels.sdk");
51 
52 static PRL_HANDLE
53 prlsdkFindNetByMAC(PRL_HANDLE sdkdom, virMacAddr *mac);
54 static PRL_HANDLE
55 prlsdkGetDisk(PRL_HANDLE sdkdom, virDomainDiskDef *disk);
56 static bool
57 prlsdkInBootList(PRL_HANDLE sdkdom,
58                  PRL_HANDLE sdktargetdev);
59 
60 /*
61  * Log error description
62  */
63 static void
logPrlErrorHelper(PRL_RESULT err,const char * filename,const char * funcname,size_t linenr)64 logPrlErrorHelper(PRL_RESULT err, const char *filename,
65                   const char *funcname, size_t linenr)
66 {
67     char *msg1 = NULL, *msg2 = NULL;
68     PRL_UINT32 len = 0;
69 
70     /* Get required buffer length */
71     PrlApi_GetResultDescription(err, PRL_TRUE, PRL_FALSE, NULL, &len);
72 
73     msg1 = g_new0(char, len);
74 
75     /* get short error description */
76     PrlApi_GetResultDescription(err, PRL_TRUE, PRL_FALSE, msg1, &len);
77 
78     PrlApi_GetResultDescription(err, PRL_FALSE, PRL_FALSE, NULL, &len);
79 
80     msg2 = g_new0(char, len);
81 
82     /* get long error description */
83     PrlApi_GetResultDescription(err, PRL_FALSE, PRL_FALSE, msg2, &len);
84 
85     virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INTERNAL_ERROR,
86                          filename, funcname, linenr,
87                          _("%s %s"), msg1, msg2);
88 
89     VIR_FREE(msg1);
90     VIR_FREE(msg2);
91 }
92 
93 #define logPrlError(code) \
94     logPrlErrorHelper(code, __FILE__, \
95                       __FUNCTION__, __LINE__)
96 
97 #define prlsdkCheckRetGoto(ret, label) \
98     do { \
99         if (PRL_FAILED(ret)) { \
100             logPrlError(ret); \
101             goto label; \
102         } \
103     } while (0)
104 
105 #define prlsdkCheckRetExit(ret, code) \
106     do { \
107         if (PRL_FAILED(ret)) { \
108             logPrlError(ret); \
109             return code; \
110         } \
111     } while (0)
112 
113 static void
logPrlEventErrorHelper(PRL_HANDLE event,const char * filename,const char * funcname,size_t linenr)114 logPrlEventErrorHelper(PRL_HANDLE event, const char *filename,
115                        const char *funcname, size_t linenr)
116 {
117     char *msg1 = NULL, *msg2 = NULL;
118     PRL_UINT32 len = 0;
119 
120     PrlEvent_GetErrString(event, PRL_TRUE, PRL_FALSE, NULL, &len);
121 
122     msg1 = g_new0(char, len);
123 
124     PrlEvent_GetErrString(event, PRL_TRUE, PRL_FALSE, msg1, &len);
125 
126     PrlEvent_GetErrString(event, PRL_FALSE, PRL_FALSE, NULL, &len);
127 
128     msg2 = g_new0(char, len);
129 
130     PrlEvent_GetErrString(event, PRL_FALSE, PRL_FALSE, msg2, &len);
131 
132     virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INTERNAL_ERROR,
133                          filename, funcname, linenr,
134                          _("%s %s"), msg1, msg2);
135     VIR_FREE(msg1);
136     VIR_FREE(msg2);
137 }
138 
139 static PRL_RESULT
getJobResultHelper(PRL_HANDLE job,unsigned int timeout,PRL_HANDLE * result,const char * filename,const char * funcname,size_t linenr)140 getJobResultHelper(PRL_HANDLE job, unsigned int timeout, PRL_HANDLE *result,
141                    const char *filename, const char *funcname,
142                    size_t linenr)
143 {
144     PRL_RESULT ret, retCode;
145 
146     if (PRL_FAILED(ret = PrlJob_Wait(job, timeout))) {
147         logPrlErrorHelper(ret, filename, funcname, linenr);
148         goto cleanup;
149     }
150 
151     if (PRL_FAILED(ret = PrlJob_GetRetCode(job, &retCode))) {
152         logPrlErrorHelper(ret, filename, funcname, linenr);
153         goto cleanup;
154     }
155 
156     if (retCode) {
157         PRL_HANDLE err_handle;
158 
159         ret = retCode;
160 
161         /* Sometimes it's possible to get additional error info. */
162         if (PRL_FAILED(retCode = PrlJob_GetError(job, &err_handle))) {
163             logPrlErrorHelper(ret, filename, funcname, linenr);
164             goto cleanup;
165         }
166 
167         if (PRL_FAILED(retCode = PrlEvent_GetErrCode(err_handle, &retCode))) {
168             logPrlErrorHelper(ret, filename, funcname, linenr);
169             if (PRL_ERR_NO_DATA != retCode)
170                 logPrlError(retCode);
171             PrlHandle_Free(err_handle);
172             goto cleanup;
173         }
174 
175         logPrlEventErrorHelper(err_handle, filename, funcname, linenr);
176 
177         PrlHandle_Free(err_handle);
178     } else {
179         ret = PrlJob_GetResult(job, result);
180         if (PRL_FAILED(ret)) {
181             logPrlErrorHelper(ret, filename, funcname, linenr);
182             PrlHandle_Free(*result);
183             *result = NULL;
184             goto cleanup;
185         }
186 
187         ret = PRL_ERR_SUCCESS;
188     }
189 
190  cleanup:
191     PrlHandle_Free(job);
192     return ret;
193 }
194 
195 #define getJobResult(job, result) \
196     getJobResultHelper(job, JOB_INFINIT_WAIT_TIMEOUT, \
197                        result, __FILE__, __FUNCTION__, __LINE__)
198 
199 static PRL_RESULT
getDomainJobResultHelper(PRL_HANDLE job,virDomainObj * dom,unsigned int timeout,PRL_HANDLE * result,const char * filename,const char * funcname,size_t linenr)200 getDomainJobResultHelper(PRL_HANDLE job, virDomainObj *dom,
201                          unsigned int timeout, PRL_HANDLE *result,
202                          const char *filename, const char *funcname,
203                          size_t linenr)
204 {
205     PRL_RESULT pret;
206 
207     if (dom)
208         virObjectUnlock(dom);
209     pret = getJobResultHelper(job, timeout, result, filename, funcname, linenr);
210     if (dom)
211         virObjectLock(dom);
212 
213     return pret;
214 }
215 
216 #define getDomainJobResult(job, dom, result) \
217     getDomainJobResultHelper(job, dom, JOB_INFINIT_WAIT_TIMEOUT, \
218                              result, __FILE__, __FUNCTION__, __LINE__)
219 
220 static PRL_RESULT
waitJobHelper(PRL_HANDLE job,unsigned int timeout,const char * filename,const char * funcname,size_t linenr)221 waitJobHelper(PRL_HANDLE job, unsigned int timeout,
222               const char *filename, const char *funcname,
223               size_t linenr)
224 {
225     PRL_HANDLE result = PRL_INVALID_HANDLE;
226     PRL_RESULT ret;
227 
228     ret = getJobResultHelper(job, timeout, &result,
229                              filename, funcname, linenr);
230     PrlHandle_Free(result);
231     return ret;
232 }
233 
234 #define waitJob(job) \
235     waitJobHelper(job, JOB_INFINIT_WAIT_TIMEOUT, __FILE__, \
236                   __FUNCTION__, __LINE__)
237 
238 static PRL_RESULT
waitDomainJobHelper(PRL_HANDLE job,virDomainObj * dom,unsigned int timeout,const char * filename,const char * funcname,size_t linenr)239 waitDomainJobHelper(PRL_HANDLE job, virDomainObj *dom, unsigned int timeout,
240                     const char *filename, const char *funcname,
241                     size_t linenr)
242 {
243     struct vzDomObj *pdom = dom->privateData;
244     PRL_RESULT ret;
245 
246     if (pdom->job.cancelled) {
247         virReportError(VIR_ERR_OPERATION_ABORTED, "%s",
248                        _("Operation cancelled by client"));
249         return PRL_ERR_FAILURE;
250     }
251 
252     pdom->job.sdkJob = job;
253 
254     virObjectUnlock(dom);
255     ret = waitJobHelper(job, timeout, filename, funcname, linenr);
256     virObjectLock(dom);
257 
258     pdom->job.sdkJob = NULL;
259 
260     return ret;
261 }
262 
263 #define waitDomainJob(job, dom) \
264     waitDomainJobHelper(job, dom, JOB_INFINIT_WAIT_TIMEOUT, __FILE__, \
265                         __FUNCTION__, __LINE__)
266 
267 typedef PRL_RESULT (*prlsdkParamGetterType)(PRL_HANDLE, char*, PRL_UINT32*);
268 
269 int
prlsdkCancelJob(virDomainObj * dom)270 prlsdkCancelJob(virDomainObj *dom)
271 {
272     struct vzDomObj *privdom = dom->privateData;
273     PRL_RESULT pret;
274     PRL_HANDLE job;
275 
276     if (!privdom->job.active) {
277         virReportError(VIR_ERR_OPERATION_INVALID,
278                        "%s", _("no job is active on the domain"));
279         return -1;
280     }
281 
282    privdom->job.cancelled = true;
283    job = PrlJob_Cancel(privdom->job.sdkJob);
284 
285    virObjectUnlock(dom);
286    pret = waitJobHelper(job, JOB_INFINIT_WAIT_TIMEOUT,
287                         __FILE__, __FUNCTION__, __LINE__);
288    virObjectLock(dom);
289 
290    return PRL_FAILED(pret) ? -1 : 0;
291 }
292 
293 static char*
prlsdkGetStringParamVar(prlsdkParamGetterType getter,PRL_HANDLE handle)294 prlsdkGetStringParamVar(prlsdkParamGetterType getter, PRL_HANDLE handle)
295 {
296     PRL_RESULT pret;
297     PRL_UINT32 buflen = 0;
298     char *str = NULL;
299 
300     pret = getter(handle, NULL, &buflen);
301     prlsdkCheckRetGoto(pret, error);
302 
303     str = g_new0(char, buflen);
304 
305     pret = getter(handle, str, &buflen);
306     prlsdkCheckRetGoto(pret, error);
307 
308     return str;
309 
310  error:
311     VIR_FREE(str);
312     return NULL;
313 }
314 
315 static PRL_RESULT
prlsdkGetStringParamBuf(prlsdkParamGetterType getter,PRL_HANDLE handle,char * buf,size_t size)316 prlsdkGetStringParamBuf(prlsdkParamGetterType getter,
317                         PRL_HANDLE handle, char *buf, size_t size)
318 {
319     PRL_UINT32 buflen = size;
320     return getter(handle, buf, &buflen);
321 }
322 
323 int
prlsdkInit(void)324 prlsdkInit(void)
325 {
326     PRL_RESULT ret;
327 
328     /* Disable console output */
329     PrlApi_SwitchConsoleLogging(0);
330 
331     ret = PrlApi_InitEx(PARALLELS_API_VER, PAM_SERVER, 0, 0);
332     if (PRL_FAILED(ret)) {
333         logPrlError(ret);
334         return -1;
335     }
336 
337     return 0;
338 };
339 
340 void
prlsdkDeinit(void)341 prlsdkDeinit(void)
342 {
343     PrlApi_Deinit();
344 };
345 
346 int
prlsdkConnect(struct _vzDriver * driver)347 prlsdkConnect(struct _vzDriver *driver)
348 {
349     int ret = -1;
350     PRL_RESULT pret;
351     PRL_HANDLE job = PRL_INVALID_HANDLE;
352     PRL_HANDLE result = PRL_INVALID_HANDLE;
353     PRL_HANDLE response = PRL_INVALID_HANDLE;
354     char session_uuid[VIR_UUID_STRING_BRACED_BUFLEN];
355 
356     pret = PrlSrv_Create(&driver->server);
357     prlsdkCheckRetExit(pret, -1);
358 
359     job = PrlSrv_LoginLocalEx(driver->server, NULL, 0,
360                               PSL_HIGH_SECURITY, PACF_NON_INTERACTIVE_MODE);
361     if (PRL_FAILED(getJobResult(job, &result)))
362         goto destroy;
363 
364     pret = PrlResult_GetParam(result, &response);
365     prlsdkCheckRetGoto(pret, logoff);
366 
367     pret = prlsdkGetStringParamBuf(PrlLoginResponse_GetSessionUuid,
368                                    response, session_uuid, sizeof(session_uuid));
369     prlsdkCheckRetGoto(pret, logoff);
370 
371     if (prlsdkUUIDParse(session_uuid, driver->session_uuid) < 0)
372         goto logoff;
373 
374     pret = PrlSrv_RegEventHandler(driver->server,
375                                   prlsdkEventsHandler,
376                                   driver);
377     prlsdkCheckRetGoto(pret, logoff);
378 
379     ret = 0;
380 
381  cleanup:
382     PrlHandle_Free(result);
383     PrlHandle_Free(response);
384 
385     return ret;
386 
387  logoff:
388     job = PrlSrv_Logoff(driver->server);
389     waitJob(job);
390 
391  destroy:
392     PrlHandle_Free(driver->server);
393     driver->server = PRL_INVALID_HANDLE;
394 
395     goto cleanup;
396 }
397 
398 void
prlsdkDisconnect(struct _vzDriver * driver)399 prlsdkDisconnect(struct _vzDriver *driver)
400 {
401     PRL_HANDLE job;
402     PRL_RESULT ret;
403 
404     if (driver->server == PRL_INVALID_HANDLE)
405         return;
406 
407     ret = PrlSrv_UnregEventHandler(driver->server,
408                                    prlsdkEventsHandler,
409                                    driver);
410     if (PRL_FAILED(ret))
411         logPrlError(ret);
412 
413     job = PrlSrv_Logoff(driver->server);
414     waitJob(job);
415 
416     PrlHandle_Free(driver->server);
417     driver->server = PRL_INVALID_HANDLE;
418 }
419 
420 static int
prlsdkSdkDomainLookup(struct _vzDriver * driver,const char * id,unsigned int flags,PRL_HANDLE * sdkdom)421 prlsdkSdkDomainLookup(struct _vzDriver *driver,
422                       const char *id,
423                       unsigned int flags,
424                       PRL_HANDLE *sdkdom)
425 {
426     PRL_HANDLE job = PRL_INVALID_HANDLE;
427     PRL_HANDLE result = PRL_INVALID_HANDLE;
428     PRL_RESULT pret = PRL_ERR_UNINITIALIZED;
429     int ret = -1;
430 
431     job = PrlSrv_GetVmConfig(driver->server, id, flags);
432     if (PRL_FAILED(getJobResult(job, &result)))
433         goto cleanup;
434 
435     pret = PrlResult_GetParamByIndex(result, 0, sdkdom);
436     prlsdkCheckRetGoto(pret, cleanup);
437 
438     ret = 0;
439 
440  cleanup:
441     PrlHandle_Free(result);
442     return ret;
443 }
444 
445 static void
prlsdkUUIDFormat(const unsigned char * uuid,char * uuidstr)446 prlsdkUUIDFormat(const unsigned char *uuid, char *uuidstr)
447 {
448     virUUIDFormat(uuid, uuidstr + 1);
449 
450     uuidstr[0] = '{';
451     uuidstr[VIR_UUID_STRING_BUFLEN] = '}';
452     uuidstr[VIR_UUID_STRING_BUFLEN + 1] = '\0';
453 }
454 
455 static PRL_HANDLE
prlsdkSdkDomainLookupByUUID(struct _vzDriver * driver,const unsigned char * uuid)456 prlsdkSdkDomainLookupByUUID(struct _vzDriver *driver, const unsigned char *uuid)
457 {
458     char uuidstr[VIR_UUID_STRING_BRACED_BUFLEN];
459     PRL_HANDLE sdkdom = PRL_INVALID_HANDLE;
460 
461     prlsdkUUIDFormat(uuid, uuidstr);
462 
463     if (prlsdkSdkDomainLookup(driver, uuidstr,
464                               PGVC_SEARCH_BY_UUID, &sdkdom) < 0) {
465         virUUIDFormat(uuid, uuidstr);
466         virReportError(VIR_ERR_NO_DOMAIN,
467                        _("no domain with matching uuid '%s'"), uuidstr);
468         return PRL_INVALID_HANDLE;
469     }
470 
471     return sdkdom;
472 }
473 
474 PRL_HANDLE
prlsdkSdkDomainLookupByName(struct _vzDriver * driver,const char * name)475 prlsdkSdkDomainLookupByName(struct _vzDriver *driver, const char *name)
476 {
477     PRL_HANDLE sdkdom = PRL_INVALID_HANDLE;
478 
479     if (prlsdkSdkDomainLookup(driver, name,
480                               PGVC_SEARCH_BY_NAME, &sdkdom) < 0) {
481         virReportError(VIR_ERR_NO_DOMAIN,
482                        _("no domain with matching name '%s'"), name);
483         return PRL_INVALID_HANDLE;
484     }
485 
486     return sdkdom;
487 }
488 
489 static int
prlsdkUUIDParse(const char * uuidstr,unsigned char * uuid)490 prlsdkUUIDParse(const char *uuidstr, unsigned char *uuid)
491 {
492     char *tmp = NULL;
493     int ret = -1;
494 
495     virCheckNonNullArgGoto(uuidstr, error);
496     virCheckNonNullArgGoto(uuid, error);
497 
498     tmp = g_strdup(uuidstr);
499 
500     tmp[strlen(tmp) - 1] = '\0';
501 
502     /* trim curly braces */
503     if (virUUIDParse(tmp + 1, uuid) < 0)
504         goto error;
505 
506     ret = 0;
507  error:
508     VIR_FREE(tmp);
509     return ret;
510 }
511 
512 static int
prlsdkGetDomainState(virDomainObj * dom,PRL_HANDLE sdkdom,VIRTUAL_MACHINE_STATE_PTR vmState)513 prlsdkGetDomainState(virDomainObj *dom, PRL_HANDLE sdkdom, VIRTUAL_MACHINE_STATE_PTR vmState)
514 {
515     PRL_HANDLE job = PRL_INVALID_HANDLE;
516     PRL_HANDLE result = PRL_INVALID_HANDLE;
517     PRL_HANDLE vmInfo = PRL_INVALID_HANDLE;
518     PRL_RESULT pret;
519     int ret = -1;
520 
521     job = PrlVm_GetState(sdkdom);
522 
523     if (PRL_FAILED(getDomainJobResult(job, dom, &result)))
524         goto cleanup;
525 
526     pret = PrlResult_GetParamByIndex(result, 0, &vmInfo);
527     prlsdkCheckRetGoto(pret, cleanup);
528 
529     pret = PrlVmInfo_GetState(vmInfo, vmState);
530     prlsdkCheckRetGoto(pret, cleanup);
531 
532     ret = 0;
533 
534  cleanup:
535     PrlHandle_Free(vmInfo);
536     PrlHandle_Free(result);
537     return ret;
538 }
539 
540 static int
prlsdkAddDomainVideoInfoCt(virDomainDef * def,virDomainXMLOption * xmlopt)541 prlsdkAddDomainVideoInfoCt(virDomainDef *def,
542                            virDomainXMLOption *xmlopt)
543 {
544     virDomainVideoDef *video = NULL;
545 
546     if (def->ngraphics == 0)
547         return 0;
548 
549     if (!(video = virDomainVideoDefNew(xmlopt)))
550         return -1;
551 
552     video->type = VIR_DOMAIN_VIDEO_TYPE_PARALLELS;
553     video->vram = 0;
554 
555     VIR_APPEND_ELEMENT(def->videos, def->nvideos, video);
556 
557     return 0;
558 }
559 
560 static int
prlsdkAddDomainVideoInfoVm(PRL_HANDLE sdkdom,virDomainDef * def)561 prlsdkAddDomainVideoInfoVm(PRL_HANDLE sdkdom, virDomainDef *def)
562 {
563     virDomainVideoDef *video = NULL;
564     virDomainVideoAccelDef *accel = NULL;
565     PRL_RESULT ret;
566     PRL_UINT32 videoRam;
567 
568     /* video info */
569     ret = PrlVmCfg_GetVideoRamSize(sdkdom, &videoRam);
570     prlsdkCheckRetGoto(ret, error);
571 
572     video = g_new0(virDomainVideoDef, 1);
573     accel = g_new0(virDomainVideoAccelDef, 1);
574 
575     VIR_APPEND_ELEMENT_COPY(def->videos, def->nvideos, video);
576 
577     video->type = VIR_DOMAIN_VIDEO_TYPE_VGA;
578     video->vram = videoRam << 10; /* from mbibytes to kbibytes */
579     video->heads = 1;
580     video->accel = accel;
581 
582     return 0;
583 }
584 
585 static int
prlsdkGetDiskId(PRL_HANDLE disk,virDomainDiskBus * bus,char ** dst)586 prlsdkGetDiskId(PRL_HANDLE disk, virDomainDiskBus *bus, char **dst)
587 {
588     PRL_RESULT pret;
589     PRL_UINT32 pos, ifType;
590 
591     pret = PrlVmDev_GetStackIndex(disk, &pos);
592     prlsdkCheckRetExit(pret, -1);
593 
594     pret = PrlVmDev_GetIfaceType(disk, &ifType);
595     prlsdkCheckRetExit(pret, -1);
596 
597     switch (ifType) {
598     case PMS_IDE_DEVICE:
599         *bus = VIR_DOMAIN_DISK_BUS_IDE;
600         *dst = virIndexToDiskName(pos, "hd");
601         break;
602     case PMS_SCSI_DEVICE:
603     case PMS_UNKNOWN_DEVICE:
604         *bus = VIR_DOMAIN_DISK_BUS_SCSI;
605         *dst = virIndexToDiskName(pos, "sd");
606         break;
607     case PMS_SATA_DEVICE:
608         *bus = VIR_DOMAIN_DISK_BUS_SATA;
609         *dst = virIndexToDiskName(pos, "sd");
610         break;
611     default:
612         virReportError(VIR_ERR_INTERNAL_ERROR,
613                        _("Unknown disk bus: %X"), ifType);
614         return -1;
615     }
616 
617     return 0;
618 }
619 
620 static int
prlsdkGetDiskInfo(struct _vzDriver * driver,PRL_HANDLE prldisk,virDomainDiskDef * disk,bool isCdrom,bool isCt)621 prlsdkGetDiskInfo(struct _vzDriver *driver,
622                   PRL_HANDLE prldisk,
623                   virDomainDiskDef *disk,
624                   bool isCdrom,
625                   bool isCt)
626 {
627     char *buf = NULL;
628     PRL_RESULT pret;
629     PRL_UINT32 emulatedType;
630     PRL_UINT32 size;
631     virDomainDeviceDriveAddress *address;
632     int busIdx, devIdx;
633     int ret = -1;
634 
635     pret = PrlVmDev_GetEmulatedType(prldisk, &emulatedType);
636     prlsdkCheckRetGoto(pret, cleanup);
637     if (emulatedType == PDT_USE_IMAGE_FILE) {
638         virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
639         if (isCdrom) {
640             virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW);
641         } else {
642             if (isCt)
643                 virDomainDiskSetFormat(disk, driver->vzCaps.ctDiskFormat);
644             else
645                 virDomainDiskSetFormat(disk, driver->vzCaps.vmDiskFormat);
646         }
647     } else {
648         virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK);
649         virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW);
650     }
651 
652     if (isCdrom) {
653         disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
654         disk->src->readonly = true;
655     } else {
656         disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
657     }
658 
659     if (!(buf = prlsdkGetStringParamVar(PrlVmDev_GetFriendlyName, prldisk)))
660         goto cleanup;
661 
662     if (*buf != '\0')
663         virDomainDiskSetSource(disk, buf);
664 
665     if (prlsdkGetDiskId(prldisk, &disk->bus, &disk->dst) < 0)
666         goto cleanup;
667 
668     if (virDiskNameToBusDeviceIndex(disk, &busIdx, &devIdx) < 0)
669         goto cleanup;
670 
671     address = &disk->info.addr.drive;
672     address->bus = busIdx;
673     address->target = 0;
674     address->unit = devIdx;
675 
676     disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
677 
678     if (!isCdrom) {
679         if (!(disk->serial = prlsdkGetStringParamVar(PrlVmDevHd_GetSerialNumber, prldisk)))
680             goto cleanup;
681 
682         if (*disk->serial == '\0')
683             VIR_FREE(disk->serial);
684     }
685 
686     virDomainDiskSetDriver(disk, "vz");
687 
688     if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
689         pret = PrlVmDevHd_GetDiskSize(prldisk, &size);
690         prlsdkCheckRetGoto(pret, cleanup);
691         /* from MiB to bytes */
692         disk->src->capacity = ((unsigned long long)size) << 20;
693     }
694 
695     ret = 0;
696 
697  cleanup:
698     VIR_FREE(buf);
699     return ret;
700 }
701 
702 static int
prlsdkGetFSInfo(PRL_HANDLE prldisk,virDomainFSDef * fs)703 prlsdkGetFSInfo(PRL_HANDLE prldisk,
704                 virDomainFSDef *fs)
705 {
706     char *buf = NULL;
707     int ret = -1;
708     g_auto(GStrv) matches = NULL;
709     virURI *uri = NULL;
710 
711     fs->type = VIR_DOMAIN_FS_TYPE_FILE;
712     fs->fsdriver = VIR_DOMAIN_FS_DRIVER_TYPE_PLOOP;
713     fs->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH;
714     fs->wrpolicy = VIR_DOMAIN_FS_WRPOLICY_DEFAULT;
715     fs->format = VIR_STORAGE_FILE_PLOOP;
716 
717     fs->readonly = false;
718     fs->symlinksResolved = false;
719 
720     if (!(buf = prlsdkGetStringParamVar(PrlVmDevHd_GetStorageURL, prldisk)))
721         goto cleanup;
722 
723     if (!virStringIsEmpty(buf)) {
724         if (!(uri = virURIParse(buf)))
725             goto cleanup;
726         if (STRNEQ("libvirt", uri->scheme)) {
727             virReportError(VIR_ERR_INTERNAL_ERROR,
728                            _("Unknown uri scheme: '%s'"),
729                            uri->scheme);
730             goto cleanup;
731         }
732 
733         if (!(matches = g_strsplit(uri->path, "/", 0)) ||
734             !matches[0]) {
735             virReportError(VIR_ERR_INTERNAL_ERROR,
736                            _("splitting StorageUrl failed %s"), uri->path);
737             goto cleanup;
738         }
739         if (!matches[1]) {
740             virReportError(VIR_ERR_INTERNAL_ERROR,
741                            _("can't identify pool in uri %s "), uri->path);
742             goto cleanup;
743         }
744         if (!matches[2]) {
745             virReportError(VIR_ERR_INTERNAL_ERROR,
746                            _("can't identify volume in uri %s"), uri->path);
747             goto cleanup;
748         }
749         fs->type = VIR_DOMAIN_FS_TYPE_VOLUME;
750         fs->src->srcpool = g_new0(virStorageSourcePoolDef, 1);
751         fs->src->srcpool->pool = g_strdup(matches[1]);
752         fs->src->srcpool->volume = g_strdup(matches[2]);
753         VIR_FREE(buf);
754     } else {
755         fs->type = VIR_DOMAIN_FS_TYPE_FILE;
756         if (!(buf = prlsdkGetStringParamVar(PrlVmDev_GetImagePath, prldisk)))
757             goto cleanup;
758 
759         fs->src->path = g_steal_pointer(&buf);
760     }
761     if (!(buf = prlsdkGetStringParamVar(PrlVmDevHd_GetMountPoint, prldisk)))
762         goto cleanup;
763 
764     fs->dst = g_steal_pointer(&buf);
765 
766     ret = 0;
767 
768  cleanup:
769     VIR_FREE(buf);
770     return ret;
771 }
772 
773 static int
prlsdkAddDomainHardDisksInfo(struct _vzDriver * driver,PRL_HANDLE sdkdom,virDomainDef * def)774 prlsdkAddDomainHardDisksInfo(struct _vzDriver *driver, PRL_HANDLE sdkdom, virDomainDef *def)
775 {
776     PRL_RESULT pret;
777     PRL_UINT32 hddCount;
778     PRL_UINT32 i;
779     PRL_HANDLE hdd = PRL_INVALID_HANDLE;
780     virDomainDiskDef *disk = NULL;
781     virDomainFSDef *fs = NULL;
782 
783     pret = PrlVmCfg_GetHardDisksCount(sdkdom, &hddCount);
784     prlsdkCheckRetGoto(pret, error);
785 
786     for (i = 0; i < hddCount; ++i) {
787 
788         PRL_UINT32 emulatedType;
789 
790         pret = PrlVmCfg_GetHardDisk(sdkdom, i, &hdd);
791         prlsdkCheckRetGoto(pret, error);
792 
793         pret = PrlVmDev_GetEmulatedType(hdd, &emulatedType);
794         prlsdkCheckRetGoto(pret, error);
795 
796         if (IS_CT(def) &&
797             prlsdkInBootList(sdkdom, hdd)) {
798 
799             if (!(fs = virDomainFSDefNew(NULL)))
800                 goto error;
801 
802             if (prlsdkGetFSInfo(hdd, fs) < 0)
803                 goto error;
804 
805             if (virDomainFSInsert(def, fs) < 0)
806                 goto error;
807 
808             fs = NULL;
809             PrlHandle_Free(hdd);
810             hdd = PRL_INVALID_HANDLE;
811         } else {
812             if (!(disk = virDomainDiskDefNew(NULL)))
813                 goto error;
814 
815             if (prlsdkGetDiskInfo(driver, hdd, disk, false, IS_CT(def)) < 0)
816                 goto error;
817 
818             virDomainDiskInsert(def, disk);
819 
820             disk = NULL;
821             PrlHandle_Free(hdd);
822             hdd = PRL_INVALID_HANDLE;
823         }
824     }
825 
826     return 0;
827 
828  error:
829     PrlHandle_Free(hdd);
830     virDomainDiskDefFree(disk);
831     virDomainFSDefFree(fs);
832     return -1;
833 }
834 
835 static int
prlsdkAddDomainOpticalDisksInfo(struct _vzDriver * driver,PRL_HANDLE sdkdom,virDomainDef * def)836 prlsdkAddDomainOpticalDisksInfo(struct _vzDriver *driver, PRL_HANDLE sdkdom, virDomainDef *def)
837 {
838     PRL_RESULT pret;
839     PRL_UINT32 cdromsCount;
840     PRL_UINT32 i;
841     PRL_HANDLE cdrom = PRL_INVALID_HANDLE;
842     virDomainDiskDef *disk = NULL;
843 
844     pret = PrlVmCfg_GetOpticalDisksCount(sdkdom, &cdromsCount);
845     prlsdkCheckRetGoto(pret, error);
846 
847     for (i = 0; i < cdromsCount; ++i) {
848         pret = PrlVmCfg_GetOpticalDisk(sdkdom, i, &cdrom);
849         prlsdkCheckRetGoto(pret, error);
850 
851         if (!(disk = virDomainDiskDefNew(NULL)))
852             goto error;
853 
854         if (prlsdkGetDiskInfo(driver, cdrom, disk, true, IS_CT(def)) < 0)
855             goto error;
856 
857         PrlHandle_Free(cdrom);
858         cdrom = PRL_INVALID_HANDLE;
859 
860         virDomainDiskInsert(def, disk);
861     }
862 
863     return 0;
864 
865  error:
866     PrlHandle_Free(cdrom);
867     virDomainDiskDefFree(disk);
868     return -1;
869 }
870 
871 static virNetDevIPAddr *
prlsdkParseNetAddress(char * addr)872 prlsdkParseNetAddress(char *addr)
873 {
874     char *maskstr = NULL;
875     int nbits;
876     virSocketAddr mask;
877     virNetDevIPAddr *ip = NULL;
878     virNetDevIPAddr *ret = NULL;
879 
880     if (!(maskstr = strchr(addr, '/')))
881         goto cleanup;
882 
883     *maskstr = '\0';
884     ++maskstr;
885 
886     ip = g_new0(virNetDevIPAddr, 1);
887 
888     if (virSocketAddrParse(&ip->address, addr, AF_UNSPEC) < 0)
889         goto cleanup;
890 
891     if (virSocketAddrParse(&mask, maskstr, AF_UNSPEC) < 0)
892         goto cleanup;
893 
894     if ((nbits = virSocketAddrGetNumNetmaskBits(&mask)) < 0)
895         goto cleanup;
896     ip->prefix = nbits;
897 
898     ret = g_steal_pointer(&ip);
899 
900  cleanup:
901     if (!ret)
902         VIR_WARN("cannot parse network address '%s'", addr);
903 
904     VIR_FREE(ip);
905     VIR_FREE(addr);
906 
907     return ret;
908 }
909 
910 static int
prlsdkGetNetAddresses(PRL_HANDLE sdknet,virDomainNetDef * net)911 prlsdkGetNetAddresses(PRL_HANDLE sdknet, virDomainNetDef *net)
912 {
913     int ret = -1;
914     PRL_HANDLE addrlist = PRL_INVALID_HANDLE;
915     PRL_UINT32 num;
916     size_t i;
917     PRL_RESULT pret;
918 
919     pret = PrlVmDevNet_GetNetAddresses(sdknet, &addrlist);
920     prlsdkCheckRetGoto(pret, cleanup);
921 
922     PrlStrList_GetItemsCount(addrlist, &num);
923     prlsdkCheckRetGoto(pret, cleanup);
924 
925     for (i = 0; i < num; ++i) {
926         virNetDevIPAddr *ip = NULL;
927         PRL_UINT32 buflen = 0;
928         char *addr;
929 
930         pret = PrlStrList_GetItem(addrlist, i, NULL, &buflen);
931         prlsdkCheckRetGoto(pret, cleanup);
932 
933         addr = g_new0(char, buflen);
934 
935         pret = PrlStrList_GetItem(addrlist, i, addr, &buflen);
936         prlsdkCheckRetGoto(pret, cleanup);
937 
938         if (!(ip = prlsdkParseNetAddress(addr)))
939             continue;
940 
941         VIR_APPEND_ELEMENT(net->guestIP.ips, net->guestIP.nips, ip);
942     }
943 
944     ret = 0;
945  cleanup:
946 
947     PrlHandle_Free(addrlist);
948     return ret;
949 }
950 
951 static int
prlsdkGetRoutes(PRL_HANDLE sdknet,virDomainNetDef * net)952 prlsdkGetRoutes(PRL_HANDLE sdknet, virDomainNetDef *net)
953 {
954     int ret = -1;
955     char *gw = NULL;
956     char *gw6 = NULL;
957     g_autoptr(virNetDevIPRoute) route = NULL;
958 
959     if (!(gw = prlsdkGetStringParamVar(PrlVmDevNet_GetDefaultGateway, sdknet)))
960         goto cleanup;
961 
962     if (!(gw6 = prlsdkGetStringParamVar(PrlVmDevNet_GetDefaultGatewayIPv6, sdknet)))
963         goto cleanup;
964 
965     if (*gw != '\0') {
966 
967         if (!(route = virNetDevIPRouteCreate(_("Domain interface"),
968                                                "ipv4", VIR_SOCKET_ADDR_IPV4_ALL,
969                                                NULL, gw, 0, true, 0, false)))
970             goto cleanup;
971 
972         VIR_APPEND_ELEMENT(net->guestIP.routes, net->guestIP.nroutes, route);
973     }
974 
975     if (*gw6 != '\0') {
976         if (!(route = virNetDevIPRouteCreate(_("Domain interface"),
977                                                "ipv6", VIR_SOCKET_ADDR_IPV6_ALL,
978                                                NULL, gw6, 0, true, 0, false)))
979             goto cleanup;
980 
981         VIR_APPEND_ELEMENT(net->guestIP.routes, net->guestIP.nroutes, route);
982     }
983 
984     ret = 0;
985 
986  cleanup:
987     VIR_FREE(gw);
988     VIR_FREE(gw6);
989 
990     return ret;
991 }
992 
993 static int
prlsdkGetNetInfo(PRL_HANDLE netAdapter,virDomainNetDef * net,bool isCt)994 prlsdkGetNetInfo(PRL_HANDLE netAdapter, virDomainNetDef *net, bool isCt)
995 {
996     char macstr[VIR_MAC_STRING_BUFLEN];
997     PRL_UINT32 netAdapterIndex;
998     PRL_UINT32 emulatedType;
999     PRL_RESULT pret;
1000     PRL_BOOL isConnected, isMacFilter;
1001 
1002     /* use device name, shown by prlctl as target device
1003      * for identifying network adapter in virDomainDefineXML */
1004     if (!(net->ifname = prlsdkGetStringParamVar(PrlVmDevNet_GetHostInterfaceName,
1005                                                 netAdapter)))
1006         return -1;
1007 
1008     pret = PrlVmDev_GetIndex(netAdapter, &netAdapterIndex);
1009     prlsdkCheckRetExit(pret, -1);
1010 
1011     if (isCt && netAdapterIndex == (PRL_UINT32) -1) {
1012         /* venet devices don't have mac address and
1013          * always up */
1014         net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP;
1015         net->type = VIR_DOMAIN_NET_TYPE_NETWORK;
1016         net->data.network.name = g_strdup(PARALLELS_DOMAIN_ROUTED_NETWORK_NAME);
1017         return 0;
1018     }
1019 
1020     pret = prlsdkGetStringParamBuf(PrlVmDevNet_GetMacAddressCanonical,
1021                                    netAdapter, macstr, sizeof(macstr));
1022     prlsdkCheckRetExit(pret, -1);
1023 
1024     if (virMacAddrParse(macstr, &net->mac) < 0)
1025         return -1;
1026 
1027     if (prlsdkGetNetAddresses(netAdapter, net) < 0)
1028         return -1;
1029 
1030     if (prlsdkGetRoutes(netAdapter, net) < 0)
1031         return -1;
1032 
1033     pret = PrlVmDev_GetEmulatedType(netAdapter, &emulatedType);
1034     prlsdkCheckRetExit(pret, -1);
1035 
1036     if (emulatedType == PNA_ROUTED) {
1037         net->type = VIR_DOMAIN_NET_TYPE_NETWORK;
1038         net->data.network.name = g_strdup(PARALLELS_DOMAIN_ROUTED_NETWORK_NAME);
1039     } else {
1040         char *netid =
1041               prlsdkGetStringParamVar(PrlVmDevNet_GetVirtualNetworkId,
1042                                       netAdapter);
1043 
1044         if (emulatedType == PNA_BRIDGE) {
1045             net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
1046             if (netid)
1047                 net->data.bridge.brname = netid;
1048         } else {
1049             net->type = VIR_DOMAIN_NET_TYPE_NETWORK;
1050             if (netid)
1051                 net->data.network.name = netid;
1052         }
1053     }
1054 
1055     if (!isCt) {
1056         PRL_VM_NET_ADAPTER_TYPE type;
1057         pret = PrlVmDevNet_GetAdapterType(netAdapter, &type);
1058         prlsdkCheckRetExit(pret, -1);
1059 
1060         switch ((int)type) {
1061         case PNT_RTL:
1062             net->model = VIR_DOMAIN_NET_MODEL_RTL8139;
1063             break;
1064         case PNT_E1000:
1065             net->model = VIR_DOMAIN_NET_MODEL_E1000;
1066             break;
1067         case PNT_VIRTIO:
1068             net->model = VIR_DOMAIN_NET_MODEL_VIRTIO;
1069             break;
1070         default:
1071             virReportError(VIR_ERR_INTERNAL_ERROR,
1072                            _("Unknown adapter type: %X"), type);
1073             return -1;
1074         }
1075     }
1076 
1077     pret = PrlVmDev_IsConnected(netAdapter, &isConnected);
1078     prlsdkCheckRetExit(pret, -1);
1079 
1080     if (isConnected)
1081         net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP;
1082     else
1083         net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN;
1084 
1085     pret = PrlVmDevNet_IsPktFilterPreventMacSpoof(netAdapter, &isMacFilter);
1086     prlsdkCheckRetExit(pret, -1);
1087 
1088     net->trustGuestRxFilters = isMacFilter ? VIR_TRISTATE_BOOL_YES :
1089                                              VIR_TRISTATE_BOOL_NO;
1090 
1091     return 0;
1092 }
1093 
1094 static int
prlsdkAddDomainNetInfo(PRL_HANDLE sdkdom,virDomainDef * def)1095 prlsdkAddDomainNetInfo(PRL_HANDLE sdkdom, virDomainDef *def)
1096 {
1097     virDomainNetDef *net = NULL;
1098     PRL_RESULT ret;
1099     PRL_HANDLE netAdapter;
1100     PRL_UINT32 netAdaptersCount;
1101     PRL_UINT32 i;
1102 
1103     ret = PrlVmCfg_GetNetAdaptersCount(sdkdom, &netAdaptersCount);
1104     prlsdkCheckRetGoto(ret, error);
1105     for (i = 0; i < netAdaptersCount; ++i) {
1106         ret = PrlVmCfg_GetNetAdapter(sdkdom, i, &netAdapter);
1107         prlsdkCheckRetGoto(ret, error);
1108 
1109         net = g_new0(virDomainNetDef, 1);
1110 
1111         if (prlsdkGetNetInfo(netAdapter, net, IS_CT(def)) < 0)
1112             goto error;
1113 
1114         PrlHandle_Free(netAdapter);
1115         netAdapter = PRL_INVALID_HANDLE;
1116 
1117         VIR_APPEND_ELEMENT(def->nets, def->nnets, net);
1118     }
1119 
1120     return 0;
1121 
1122  error:
1123     PrlHandle_Free(netAdapter);
1124     virDomainNetDefFree(net);
1125     return -1;
1126 }
1127 
1128 static int
prlsdkGetSerialInfo(PRL_HANDLE serialPort,virDomainChrDef * chr)1129 prlsdkGetSerialInfo(PRL_HANDLE serialPort, virDomainChrDef *chr)
1130 {
1131     PRL_RESULT pret;
1132     PRL_UINT32 serialPortIndex;
1133     PRL_UINT32 emulatedType;
1134     char *friendlyName = NULL;
1135     PRL_SERIAL_PORT_SOCKET_OPERATION_MODE socket_mode;
1136     char *uristr = NULL;
1137     virURI *uri = NULL;
1138     int ret = -1;
1139 
1140     chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
1141     pret = PrlVmDev_GetIndex(serialPort, &serialPortIndex);
1142     prlsdkCheckRetGoto(pret, cleanup);
1143     chr->target.port = serialPortIndex;
1144 
1145     pret = PrlVmDev_GetEmulatedType(serialPort, &emulatedType);
1146     prlsdkCheckRetGoto(pret, cleanup);
1147 
1148     if (!(friendlyName = prlsdkGetStringParamVar(PrlVmDev_GetFriendlyName,
1149                                                  serialPort)))
1150         goto cleanup;
1151 
1152     pret = PrlVmDevSerial_GetSocketMode(serialPort, &socket_mode);
1153     prlsdkCheckRetGoto(pret, cleanup);
1154 
1155     switch (emulatedType) {
1156     case PDT_USE_OUTPUT_FILE:
1157         chr->source->type = VIR_DOMAIN_CHR_TYPE_FILE;
1158         chr->source->data.file.path = g_steal_pointer(&friendlyName);
1159         break;
1160     case PDT_USE_SERIAL_PORT_SOCKET_MODE:
1161         chr->source->type = VIR_DOMAIN_CHR_TYPE_UNIX;
1162         chr->source->data.nix.path = g_steal_pointer(&friendlyName);
1163         chr->source->data.nix.listen = socket_mode == PSP_SERIAL_SOCKET_SERVER;
1164         break;
1165     case PDT_USE_REAL_DEVICE:
1166         chr->source->type = VIR_DOMAIN_CHR_TYPE_DEV;
1167         chr->source->data.file.path = g_steal_pointer(&friendlyName);
1168         break;
1169     case PDT_USE_TCP:
1170         chr->source->type = VIR_DOMAIN_CHR_TYPE_TCP;
1171         uristr = g_strdup_printf("tcp://%s", friendlyName);
1172         if (!(uri = virURIParse(uristr)))
1173             goto cleanup;
1174         chr->source->data.tcp.host = g_strdup(uri->server);
1175         chr->source->data.tcp.service = g_strdup_printf("%d", uri->port);
1176         chr->source->data.tcp.listen = socket_mode == PSP_SERIAL_SOCKET_SERVER;
1177         break;
1178     case PDT_USE_UDP:
1179         chr->source->type = VIR_DOMAIN_CHR_TYPE_UDP;
1180         uristr = g_strdup_printf("udp://%s", friendlyName);
1181         if (!(uri = virURIParse(uristr)))
1182             goto cleanup;
1183         chr->source->data.udp.bindHost = g_strdup(uri->server);
1184         chr->source->data.udp.bindService = g_strdup_printf("%d", uri->port);
1185         chr->source->data.udp.connectHost = g_strdup(uri->server);
1186         chr->source->data.udp.connectService = g_strdup_printf("%d", uri->port);
1187         break;
1188     default:
1189         virReportError(VIR_ERR_INTERNAL_ERROR,
1190                        _("Unknown serial type: %X"), emulatedType);
1191         goto cleanup;
1192         break;
1193     }
1194 
1195     ret = 0;
1196 
1197  cleanup:
1198     VIR_FREE(friendlyName);
1199     VIR_FREE(uristr);
1200     virURIFree(uri);
1201 
1202     return ret;
1203 }
1204 
1205 
1206 static int
prlsdkAddSerialInfo(PRL_HANDLE sdkdom,virDomainChrDef *** serials,size_t * nserials)1207 prlsdkAddSerialInfo(PRL_HANDLE sdkdom,
1208                     virDomainChrDef ***serials,
1209                     size_t *nserials)
1210 {
1211     PRL_RESULT ret;
1212     PRL_HANDLE serialPort;
1213     PRL_UINT32 serialPortsCount;
1214     PRL_UINT32 i;
1215     virDomainChrDef *chr = NULL;
1216 
1217     ret = PrlVmCfg_GetSerialPortsCount(sdkdom, &serialPortsCount);
1218     prlsdkCheckRetGoto(ret, cleanup);
1219     for (i = 0; i < serialPortsCount; ++i) {
1220         ret = PrlVmCfg_GetSerialPort(sdkdom, i, &serialPort);
1221         prlsdkCheckRetGoto(ret, cleanup);
1222 
1223         if (!(chr = virDomainChrDefNew(NULL)))
1224             goto cleanup;
1225 
1226         if (prlsdkGetSerialInfo(serialPort, chr))
1227             goto cleanup;
1228 
1229         PrlHandle_Free(serialPort);
1230         serialPort = PRL_INVALID_HANDLE;
1231 
1232         VIR_APPEND_ELEMENT(*serials, *nserials, chr);
1233     }
1234 
1235     return 0;
1236 
1237  cleanup:
1238     PrlHandle_Free(serialPort);
1239     virDomainChrDefFree(chr);
1240     return -1;
1241 }
1242 
1243 
1244 static int
prlsdkAddDomainHardware(struct _vzDriver * driver,PRL_HANDLE sdkdom,virDomainDef * def,virDomainXMLOption * xmlopt)1245 prlsdkAddDomainHardware(struct _vzDriver *driver,
1246                         PRL_HANDLE sdkdom,
1247                         virDomainDef *def,
1248                         virDomainXMLOption *xmlopt)
1249 {
1250     if (IS_CT(def)) {
1251         if (prlsdkAddDomainVideoInfoCt(def, xmlopt) < 0)
1252             return -1;
1253     } else {
1254         if (prlsdkAddDomainVideoInfoVm(sdkdom, def) < 0)
1255             return -1;
1256     }
1257 
1258     if (prlsdkAddDomainHardDisksInfo(driver, sdkdom, def) < 0)
1259         return -1;
1260 
1261     if (prlsdkAddDomainOpticalDisksInfo(driver, sdkdom, def) < 0)
1262         return -1;
1263 
1264     if (prlsdkAddDomainNetInfo(sdkdom, def) < 0)
1265         return -1;
1266 
1267     if (prlsdkAddSerialInfo(sdkdom,
1268                             &def->serials,
1269                             &def->nserials) < 0)
1270         return -1;
1271 
1272     return 0;
1273 }
1274 
1275 
1276 static int
prlsdkAddVNCInfo(PRL_HANDLE sdkdom,virDomainDef * def)1277 prlsdkAddVNCInfo(PRL_HANDLE sdkdom, virDomainDef *def)
1278 {
1279     virDomainGraphicsDef *gr = NULL;
1280     PRL_VM_REMOTE_DISPLAY_MODE vncMode;
1281     PRL_UINT32 port;
1282     PRL_RESULT pret;
1283     char *passwd = NULL;
1284 
1285     pret = PrlVmCfg_GetVNCMode(sdkdom, &vncMode);
1286     prlsdkCheckRetGoto(pret, error);
1287 
1288     if (vncMode == PRD_DISABLED)
1289         return 0;
1290 
1291     gr = g_new0(virDomainGraphicsDef, 1);
1292 
1293     if (!(passwd = prlsdkGetStringParamVar(PrlVmCfg_GetVNCPassword, sdkdom)))
1294         goto error;
1295 
1296     if (*passwd != '\0') {
1297         gr->data.vnc.auth.passwd = g_steal_pointer(&passwd);
1298     }
1299 
1300     pret = PrlVmCfg_GetVNCPort(sdkdom, &port);
1301     prlsdkCheckRetGoto(pret, error);
1302 
1303     gr->data.vnc.autoport = (vncMode == PRD_AUTO);
1304     gr->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
1305     gr->data.vnc.port = port;
1306 
1307     gr->listens = g_new0(virDomainGraphicsListenDef, 1);
1308     gr->nListens = 1;
1309 
1310     if (!(gr->listens[0].address = prlsdkGetStringParamVar(PrlVmCfg_GetVNCHostName,
1311                                                            sdkdom)))
1312         goto error;
1313 
1314     gr->listens[0].type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS;
1315 
1316     VIR_APPEND_ELEMENT(def->graphics, def->ngraphics, gr);
1317 
1318     return 0;
1319 
1320  error:
1321     virDomainGraphicsDefFree(gr);
1322     VIR_FREE(passwd);
1323     return -1;
1324 }
1325 
1326 static void
prlsdkConvertDomainState(VIRTUAL_MACHINE_STATE domainState,PRL_UINT32 envId,virDomainObj * dom)1327 prlsdkConvertDomainState(VIRTUAL_MACHINE_STATE domainState,
1328                          PRL_UINT32 envId,
1329                          virDomainObj *dom)
1330 {
1331     switch (domainState) {
1332     case VMS_STOPPED:
1333     case VMS_MOUNTED:
1334         virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF,
1335                              VIR_DOMAIN_SHUTOFF_SHUTDOWN);
1336         dom->def->id = -1;
1337         break;
1338     case VMS_STARTING:
1339     case VMS_COMPACTING:
1340     case VMS_RESETTING:
1341     case VMS_PAUSING:
1342     case VMS_RECONNECTING:
1343     case VMS_RUNNING:
1344         virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
1345                              VIR_DOMAIN_RUNNING_BOOTED);
1346         dom->def->id = envId;
1347         break;
1348     case VMS_PAUSED:
1349         virDomainObjSetState(dom, VIR_DOMAIN_PAUSED,
1350                              VIR_DOMAIN_PAUSED_USER);
1351         dom->def->id = envId;
1352         break;
1353     case VMS_SUSPENDED:
1354     case VMS_DELETING_STATE:
1355     case VMS_SUSPENDING_SYNC:
1356         virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF,
1357                              VIR_DOMAIN_SHUTOFF_SAVED);
1358         dom->def->id = -1;
1359         break;
1360     case VMS_STOPPING:
1361         virDomainObjSetState(dom, VIR_DOMAIN_SHUTDOWN,
1362                              VIR_DOMAIN_SHUTDOWN_USER);
1363         dom->def->id = envId;
1364         break;
1365     case VMS_SNAPSHOTING:
1366         virDomainObjSetState(dom, VIR_DOMAIN_PAUSED,
1367                              VIR_DOMAIN_PAUSED_SNAPSHOT);
1368         dom->def->id = envId;
1369         break;
1370     case VMS_MIGRATING:
1371         virDomainObjSetState(dom, VIR_DOMAIN_PAUSED,
1372                              VIR_DOMAIN_PAUSED_MIGRATION);
1373         dom->def->id = envId;
1374         break;
1375     case VMS_SUSPENDING:
1376         virDomainObjSetState(dom, VIR_DOMAIN_PAUSED,
1377                              VIR_DOMAIN_PAUSED_SAVE);
1378         dom->def->id = envId;
1379         break;
1380     case VMS_RESTORING:
1381         virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
1382                              VIR_DOMAIN_RUNNING_RESTORED);
1383         dom->def->id = envId;
1384         break;
1385     case VMS_CONTINUING:
1386         virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
1387                              VIR_DOMAIN_RUNNING_UNPAUSED);
1388         dom->def->id = envId;
1389         break;
1390     case VMS_RESUMING:
1391         virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
1392                              VIR_DOMAIN_RUNNING_RESTORED);
1393         dom->def->id = envId;
1394         break;
1395     case VMS_UNKNOWN:
1396     default:
1397         virDomainObjSetState(dom, VIR_DOMAIN_NOSTATE,
1398                              VIR_DOMAIN_NOSTATE_UNKNOWN);
1399         dom->def->id = -1;
1400         break;
1401     }
1402 }
1403 
1404 static int
prlsdkConvertCpuInfo(PRL_HANDLE sdkdom,virDomainDef * def,virDomainXMLOption * xmlopt)1405 prlsdkConvertCpuInfo(PRL_HANDLE sdkdom,
1406                      virDomainDef *def,
1407                      virDomainXMLOption *xmlopt)
1408 {
1409     g_autofree char *buf = NULL;
1410     int hostcpus;
1411     PRL_UINT32 cpuCount;
1412     PRL_RESULT pret;
1413 
1414     if ((hostcpus = virHostCPUGetCount()) < 0)
1415         return -1;
1416 
1417     /* get number of CPUs */
1418     pret = PrlVmCfg_GetCpuCount(sdkdom, &cpuCount);
1419     prlsdkCheckRetExit(pret, -1);
1420 
1421     if (cpuCount > hostcpus)
1422         cpuCount = hostcpus;
1423 
1424     if (virDomainDefSetVcpusMax(def, cpuCount, xmlopt) < 0)
1425         return -1;
1426 
1427     if (virDomainDefSetVcpus(def, cpuCount) < 0)
1428         return -1;
1429 
1430     if (!(buf = prlsdkGetStringParamVar(PrlVmCfg_GetCpuMask, sdkdom)))
1431         return -1;
1432 
1433     if (strlen(buf) == 0) {
1434         def->cpumask = virBitmapNew(hostcpus);
1435         virBitmapSetAll(def->cpumask);
1436     } else {
1437         if (virBitmapParse(buf, &def->cpumask, hostcpus) < 0)
1438             return -1;
1439     }
1440 
1441     return 0;
1442 }
1443 
1444 static int
prlsdkConvertDomainType(PRL_HANDLE sdkdom,virDomainDef * def)1445 prlsdkConvertDomainType(PRL_HANDLE sdkdom, virDomainDef *def)
1446 {
1447     PRL_VM_TYPE domainType;
1448     PRL_RESULT pret;
1449 
1450     pret = PrlVmCfg_GetVmType(sdkdom, &domainType);
1451     prlsdkCheckRetExit(pret, -1);
1452 
1453     switch (domainType) {
1454     case PVT_VM:
1455         def->os.type = VIR_DOMAIN_OSTYPE_HVM;
1456         break;
1457     case PVT_CT:
1458         def->os.type = VIR_DOMAIN_OSTYPE_EXE;
1459         def->os.init = g_strdup("/sbin/init");
1460         break;
1461     default:
1462         virReportError(VIR_ERR_INTERNAL_ERROR,
1463                        _("Unknown domain type: %X"), domainType);
1464         return -1;
1465     }
1466 
1467     return 0;
1468 }
1469 
1470 static int
prlsdkConvertCpuMode(PRL_HANDLE sdkdom,virDomainDef * def)1471 prlsdkConvertCpuMode(PRL_HANDLE sdkdom, virDomainDef *def)
1472 {
1473     PRL_RESULT pret;
1474     PRL_CPU_MODE cpuMode;
1475 
1476     pret = PrlVmCfg_GetCpuMode(sdkdom, &cpuMode);
1477     prlsdkCheckRetExit(pret, -1);
1478 
1479     switch (cpuMode) {
1480     case PCM_CPU_MODE_32:
1481         def->os.arch = VIR_ARCH_I686;
1482         break;
1483     case PCM_CPU_MODE_64:
1484         def->os.arch = VIR_ARCH_X86_64;
1485         break;
1486     default:
1487         virReportError(VIR_ERR_INTERNAL_ERROR,
1488                        _("Unknown CPU mode: %X"), cpuMode);
1489         return -1;
1490     }
1491 
1492     return 0;
1493 }
1494 
1495 static PRL_HANDLE
prlsdkGetDevByDevIndex(PRL_HANDLE sdkdom,PRL_DEVICE_TYPE type,PRL_UINT32 devIndex)1496 prlsdkGetDevByDevIndex(PRL_HANDLE sdkdom, PRL_DEVICE_TYPE type, PRL_UINT32 devIndex)
1497 {
1498     PRL_RESULT pret;
1499     PRL_UINT32 index, num;
1500     PRL_HANDLE dev = PRL_INVALID_HANDLE;
1501     size_t i;
1502 
1503     pret = PrlVmCfg_GetDevsCountByType(sdkdom, type, &num);
1504     prlsdkCheckRetGoto(pret, error);
1505 
1506     for (i = 0; i < num; ++i) {
1507         pret = PrlVmCfg_GetDevByType(sdkdom, type, i, &dev);
1508         prlsdkCheckRetGoto(pret, error);
1509 
1510         pret = PrlVmDev_GetIndex(dev, &index);
1511         prlsdkCheckRetGoto(pret, error);
1512 
1513         if (index == devIndex)
1514             break;
1515 
1516         PrlHandle_Free(dev);
1517         dev = PRL_INVALID_HANDLE;
1518     }
1519 
1520     return dev;
1521 
1522  error:
1523     PrlHandle_Free(dev);
1524     return PRL_INVALID_HANDLE;
1525 }
1526 
1527 static virDomainDiskDef *
virFindDiskBootIndex(virDomainDef * def,virDomainDiskDevice type,int index)1528 virFindDiskBootIndex(virDomainDef *def, virDomainDiskDevice type, int index)
1529 {
1530     size_t i;
1531     int c = 0;
1532 
1533     for (i = 0; i < def->ndisks; ++i) {
1534         if (def->disks[i]->device != type)
1535             continue;
1536         if (c == index)
1537             return def->disks[i];
1538         ++c;
1539     }
1540 
1541     return NULL;
1542 }
1543 
1544 static bool
prlsdkInBootList(PRL_HANDLE sdkdom,PRL_HANDLE sdktargetdev)1545 prlsdkInBootList(PRL_HANDLE sdkdom,
1546                  PRL_HANDLE sdktargetdev)
1547 {
1548     bool ret = false;
1549     PRL_RESULT pret;
1550     PRL_UINT32 bootNum;
1551     PRL_HANDLE bootDev = PRL_INVALID_HANDLE;
1552     PRL_BOOL inUse;
1553     PRL_DEVICE_TYPE sdkType, targetType;
1554     PRL_UINT32 sdkIndex, targetIndex;
1555     size_t i;
1556 
1557     pret = PrlVmDev_GetType(sdktargetdev, &targetType);
1558     prlsdkCheckRetExit(pret, false);
1559 
1560     pret = PrlVmDev_GetIndex(sdktargetdev, &targetIndex);
1561     prlsdkCheckRetExit(pret, false);
1562 
1563     pret = PrlVmCfg_GetBootDevCount(sdkdom, &bootNum);
1564     prlsdkCheckRetExit(pret, false);
1565 
1566     for (i = 0; i < bootNum; ++i) {
1567         pret = PrlVmCfg_GetBootDev(sdkdom, i, &bootDev);
1568         prlsdkCheckRetGoto(pret, cleanup);
1569 
1570         pret = PrlBootDev_IsInUse(bootDev, &inUse);
1571         prlsdkCheckRetGoto(pret, cleanup);
1572 
1573         if (!inUse) {
1574             PrlHandle_Free(bootDev);
1575             bootDev = PRL_INVALID_HANDLE;
1576             continue;
1577         }
1578 
1579         pret = PrlBootDev_GetType(bootDev, &sdkType);
1580         prlsdkCheckRetGoto(pret, cleanup);
1581 
1582         pret = PrlBootDev_GetIndex(bootDev, &sdkIndex);
1583         prlsdkCheckRetGoto(pret, cleanup);
1584 
1585         PrlHandle_Free(bootDev);
1586         bootDev = PRL_INVALID_HANDLE;
1587 
1588         if (sdkIndex == targetIndex && sdkType == targetType) {
1589             ret = true;
1590             break;
1591         }
1592     }
1593 
1594  cleanup:
1595     PrlHandle_Free(bootDev);
1596     return ret;
1597 }
1598 static int
prlsdkBootOrderCheck(PRL_HANDLE sdkdom,PRL_DEVICE_TYPE sdkType,int sdkIndex,virDomainDef * def,int bootIndex)1599 prlsdkBootOrderCheck(PRL_HANDLE sdkdom, PRL_DEVICE_TYPE sdkType, int sdkIndex,
1600                      virDomainDef *def, int bootIndex)
1601 {
1602     char *sdkName = NULL;
1603     PRL_HANDLE dev = PRL_INVALID_HANDLE;
1604     virDomainDiskDef *disk;
1605     virDomainDiskDevice device;
1606     virDomainDiskBus bus;
1607     char *dst = NULL;
1608     int ret = -1;
1609 
1610     dev = prlsdkGetDevByDevIndex(sdkdom, sdkType, sdkIndex);
1611     if (dev == PRL_INVALID_HANDLE) {
1612         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1613                        _("Can't find boot device of type: %d, device index: %d"),
1614                        sdkType, sdkIndex);
1615         return -1;
1616     }
1617 
1618     switch ((int)sdkType) {
1619     case PDE_OPTICAL_DISK:
1620     case PDE_HARD_DISK:
1621         switch ((int)sdkType) {
1622         case PDE_OPTICAL_DISK:
1623             device = VIR_DOMAIN_DISK_DEVICE_CDROM;
1624             break;
1625         case PDE_HARD_DISK:
1626             device = VIR_DOMAIN_DISK_DEVICE_DISK;
1627             break;
1628         default:
1629             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1630                            _("Unsupported disk type %d"), sdkType);
1631             goto cleanup;
1632         }
1633 
1634         if (!(disk = virFindDiskBootIndex(def, device, bootIndex))) {
1635             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1636                            _("Can't find boot device of type: %s, index: %d"),
1637                            virDomainDiskDeviceTypeToString(device), bootIndex);
1638             goto cleanup;
1639         }
1640 
1641         if (prlsdkGetDiskId(dev, &bus, &dst) < 0)
1642             goto cleanup;
1643 
1644         if (!(bus == disk->bus && STREQ(disk->dst, dst)))
1645             VIR_WARN("Unrepresentable boot order configuration");
1646 
1647         break;
1648     case PDE_GENERIC_NETWORK_ADAPTER:
1649         if (!(sdkName = prlsdkGetStringParamVar(PrlVmDevNet_GetHostInterfaceName,
1650                                                 dev)))
1651             goto cleanup;
1652 
1653         if (bootIndex >= def->nnets) {
1654             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1655                            _("Can't find network boot device for index: %d"),
1656                            bootIndex);
1657             goto cleanup;
1658         }
1659 
1660         if (STRNEQ(sdkName, def->nets[bootIndex]->ifname))
1661             VIR_WARN("Unrepresentable boot order configuration");
1662 
1663         break;
1664     default:
1665         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1666                        _("Unexpected device type %d"), sdkType);
1667         goto cleanup;
1668     }
1669 
1670     ret = 0;
1671 
1672  cleanup:
1673 
1674     VIR_FREE(sdkName);
1675     PrlHandle_Free(dev);
1676     VIR_FREE(dst);
1677     return ret;
1678 }
1679 
1680 static int
prlsdkConvertBootOrderVm(PRL_HANDLE sdkdom,virDomainDef * def)1681 prlsdkConvertBootOrderVm(PRL_HANDLE sdkdom, virDomainDef *def)
1682 {
1683     int ret = -1;
1684     PRL_RESULT pret;
1685     PRL_UINT32 bootNum;
1686     PRL_HANDLE bootDev = PRL_INVALID_HANDLE;
1687     PRL_BOOL inUse;
1688     PRL_DEVICE_TYPE sdkType;
1689     virDomainBootOrder type;
1690     PRL_UINT32 prevBootIndex = 0, bootIndex, sdkIndex;
1691     int bootUsage[VIR_DOMAIN_BOOT_LAST] = { 0 };
1692     size_t i;
1693 
1694     pret = PrlVmCfg_GetBootDevCount(sdkdom, &bootNum);
1695     prlsdkCheckRetExit(pret, -1);
1696 
1697     def->os.nBootDevs = 0;
1698 
1699     if (bootNum > VIR_DOMAIN_MAX_BOOT_DEVS) {
1700         bootNum = VIR_DOMAIN_MAX_BOOT_DEVS;
1701         VIR_WARN("Too many boot devices");
1702     }
1703 
1704     for (i = 0; i < bootNum; ++i) {
1705         pret = PrlVmCfg_GetBootDev(sdkdom, i, &bootDev);
1706         prlsdkCheckRetGoto(pret, cleanup);
1707 
1708         pret = PrlBootDev_IsInUse(bootDev, &inUse);
1709         prlsdkCheckRetGoto(pret, cleanup);
1710 
1711         if (!inUse)
1712             continue;
1713 
1714         pret = PrlBootDev_GetSequenceIndex(bootDev, &bootIndex);
1715         prlsdkCheckRetGoto(pret, cleanup);
1716 
1717         /* bootIndex is started from 1 */
1718         if (bootIndex <= prevBootIndex) {
1719             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1720                            _("Unsupported boot order configuration"));
1721             goto cleanup;
1722         }
1723         prevBootIndex = bootIndex;
1724 
1725         pret = PrlBootDev_GetType(bootDev, &sdkType);
1726         prlsdkCheckRetGoto(pret, cleanup);
1727 
1728         if (sdkType == PDE_FLOPPY_DISK) {
1729             VIR_WARN("Skipping floppy from boot order.");
1730             continue;
1731         }
1732 
1733         switch ((int)sdkType) {
1734         case PDE_OPTICAL_DISK:
1735             type = VIR_DOMAIN_BOOT_CDROM;
1736             break;
1737         case PDE_HARD_DISK:
1738             type = VIR_DOMAIN_BOOT_DISK;
1739             break;
1740         case PDE_GENERIC_NETWORK_ADAPTER:
1741             type = VIR_DOMAIN_BOOT_NET;
1742             break;
1743         default:
1744             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1745                            _("Unexpected boot device type %i"), sdkType);
1746             goto cleanup;
1747         }
1748 
1749         pret = PrlBootDev_GetIndex(bootDev, &sdkIndex);
1750         prlsdkCheckRetGoto(pret, cleanup);
1751 
1752         if (prlsdkBootOrderCheck(sdkdom, sdkType, sdkIndex, def, bootUsage[type]) < 0)
1753             goto cleanup;
1754 
1755         bootUsage[type]++;
1756         def->os.bootDevs[def->os.nBootDevs++] = type;
1757 
1758         PrlHandle_Free(bootDev);
1759         bootDev = PRL_INVALID_HANDLE;
1760     }
1761 
1762     ret = 0;
1763 
1764  cleanup:
1765     PrlHandle_Free(bootDev);
1766     return ret;
1767 }
1768 
1769 /* if dom is NULL adds new domain into domain list
1770  * if dom not NULL updates given locked dom object.
1771  *
1772  * Returned object is locked and referenced.
1773  */
1774 
1775 static virDomainObj *
prlsdkLoadDomain(struct _vzDriver * driver,PRL_HANDLE sdkdom,virDomainObj * dom)1776 prlsdkLoadDomain(struct _vzDriver *driver,
1777                  PRL_HANDLE sdkdom,
1778                  virDomainObj *dom)
1779 {
1780     virDomainDef *def = NULL;
1781     struct vzDomObj *pdom = NULL;
1782     VIRTUAL_MACHINE_STATE domainState;
1783 
1784     PRL_RESULT pret;
1785     PRL_UINT32 ram;
1786     PRL_UINT32 envId;
1787     PRL_VM_AUTOSTART_OPTION autostart;
1788     PRL_HANDLE job;
1789     char uuidstr[VIR_UUID_STRING_BRACED_BUFLEN];
1790 
1791     if (!(def = virDomainDefNew(driver->xmlopt)))
1792         goto error;
1793 
1794     if (!(def->name = prlsdkGetStringParamVar(PrlVmCfg_GetName, sdkdom)))
1795         goto error;
1796 
1797     pret = prlsdkGetStringParamBuf(PrlVmCfg_GetUuid,
1798                                    sdkdom, uuidstr, sizeof(uuidstr));
1799     prlsdkCheckRetGoto(pret, error);
1800 
1801     if (prlsdkUUIDParse(uuidstr, def->uuid) < 0) {
1802         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1803                        _("Domain UUID is malformed or empty"));
1804         goto error;
1805     }
1806 
1807     def->virtType = VIR_DOMAIN_VIRT_VZ;
1808 
1809     def->onReboot = VIR_DOMAIN_LIFECYCLE_ACTION_RESTART;
1810     def->onPoweroff = VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY;
1811     def->onCrash = VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY;
1812 
1813     /* get RAM parameters */
1814     pret = PrlVmCfg_GetRamSize(sdkdom, &ram);
1815     prlsdkCheckRetGoto(pret, error);
1816     virDomainDefSetMemoryTotal(def, ram << 10); /* RAM size obtained in Mbytes,
1817                                                      convert to Kbytes */
1818     def->mem.cur_balloon = ram << 10;
1819 
1820     if (prlsdkConvertCpuInfo(sdkdom, def, driver->xmlopt) < 0)
1821         goto error;
1822 
1823     if (prlsdkConvertCpuMode(sdkdom, def) < 0)
1824         goto error;
1825 
1826     if (prlsdkConvertDomainType(sdkdom, def) < 0)
1827         goto error;
1828 
1829     if (prlsdkAddVNCInfo(sdkdom, def) < 0)
1830         goto error;
1831 
1832     /* depends on prlsdkAddVNCInfo */
1833     if (prlsdkAddDomainHardware(driver, sdkdom, def, driver->xmlopt) < 0)
1834         goto error;
1835 
1836     /* depends on prlsdkAddDomainHardware */
1837     if (!IS_CT(def) && prlsdkConvertBootOrderVm(sdkdom, def) < 0)
1838         goto error;
1839 
1840     pret = PrlVmCfg_GetEnvId(sdkdom, &envId);
1841     prlsdkCheckRetGoto(pret, error);
1842 
1843     pret = PrlVmCfg_GetAutoStart(sdkdom, &autostart);
1844     prlsdkCheckRetGoto(pret, error);
1845     if (autostart != PAO_VM_START_ON_LOAD &&
1846         autostart != PAO_VM_START_MANUAL) {
1847         virReportError(VIR_ERR_INTERNAL_ERROR,
1848                        _("Unknown autostart mode: %X"), autostart);
1849         goto error;
1850     }
1851 
1852     if (prlsdkGetDomainState(dom, sdkdom, &domainState) < 0)
1853         goto error;
1854 
1855     if (!IS_CT(def) && virDomainDefAddImplicitDevices(def, driver->xmlopt) < 0)
1856         goto error;
1857 
1858     if (def->ngraphics > 0) {
1859         int bus = IS_CT(def) ? VIR_DOMAIN_INPUT_BUS_PARALLELS :
1860                                VIR_DOMAIN_INPUT_BUS_PS2;
1861 
1862         if (virDomainDefMaybeAddInput(def,
1863                                       VIR_DOMAIN_INPUT_TYPE_MOUSE,
1864                                       bus) < 0)
1865             goto error;
1866 
1867         if (virDomainDefMaybeAddInput(def,
1868                                       VIR_DOMAIN_INPUT_TYPE_KBD,
1869                                       bus) < 0)
1870             goto error;
1871     }
1872 
1873     if (!dom) {
1874         virDomainObj *olddom = NULL;
1875 
1876         job = PrlVm_SubscribeToPerfStats(sdkdom, NULL);
1877         if (PRL_FAILED(waitJob(job)))
1878             goto error;
1879 
1880         virObjectLock(driver);
1881         if (!(olddom = virDomainObjListFindByUUID(driver->domains, def->uuid)))
1882             dom = virDomainObjListAdd(driver->domains, def, driver->xmlopt, 0, NULL);
1883         virObjectUnlock(driver);
1884 
1885         if (olddom) {
1886             virDomainDefFree(def);
1887             return olddom;
1888         } else if (!dom) {
1889             goto error;
1890         }
1891 
1892         pdom = dom->privateData;
1893         pdom->sdkdom = sdkdom;
1894         PrlHandle_AddRef(sdkdom);
1895         dom->persistent = 1;
1896     } else {
1897         /* assign new virDomainDef without any checks
1898          * we can't use virDomainObjAssignDef, because it checks
1899          * for state and domain name */
1900         virDomainDefFree(dom->def);
1901         dom->def = def;
1902     }
1903 
1904     pdom = dom->privateData;
1905     pdom->id = envId;
1906 
1907     prlsdkConvertDomainState(domainState, envId, dom);
1908 
1909     if (autostart == PAO_VM_START_ON_LOAD)
1910         dom->autostart = 1;
1911     else
1912         dom->autostart = 0;
1913 
1914     return dom;
1915 
1916  error:
1917     virDomainDefFree(def);
1918     return NULL;
1919 }
1920 
1921 int
prlsdkLoadDomains(struct _vzDriver * driver)1922 prlsdkLoadDomains(struct _vzDriver *driver)
1923 {
1924     PRL_HANDLE job = PRL_INVALID_HANDLE;
1925     PRL_HANDLE result;
1926     PRL_HANDLE sdkdom = PRL_INVALID_HANDLE;
1927     PRL_UINT32 paramsCount;
1928     PRL_RESULT pret;
1929     size_t i = 0;
1930     virDomainObj *dom;
1931 
1932     job = PrlSrv_GetVmListEx(driver->server, PVTF_VM | PVTF_CT);
1933 
1934     if (PRL_FAILED(getJobResult(job, &result)))
1935         return -1;
1936 
1937     pret = PrlResult_GetParamsCount(result, &paramsCount);
1938     prlsdkCheckRetGoto(pret, error);
1939 
1940     for (i = 0; i < paramsCount; i++) {
1941         pret = PrlResult_GetParamByIndex(result, i, &sdkdom);
1942         prlsdkCheckRetGoto(pret, error);
1943 
1944         dom = prlsdkLoadDomain(driver, sdkdom, NULL);
1945         virDomainObjEndAPI(&dom);
1946 
1947         PrlHandle_Free(sdkdom);
1948         sdkdom = PRL_INVALID_HANDLE;
1949     }
1950 
1951     PrlHandle_Free(result);
1952     return 0;
1953 
1954  error:
1955     PrlHandle_Free(sdkdom);
1956     PrlHandle_Free(result);
1957     return -1;
1958 }
1959 
1960 virDomainObj *
prlsdkAddDomainByUUID(struct _vzDriver * driver,const unsigned char * uuid)1961 prlsdkAddDomainByUUID(struct _vzDriver *driver, const unsigned char *uuid)
1962 {
1963     PRL_HANDLE sdkdom;
1964     virDomainObj *dom;
1965 
1966     sdkdom = prlsdkSdkDomainLookupByUUID(driver, uuid);
1967     if (sdkdom == PRL_INVALID_HANDLE)
1968         return NULL;
1969 
1970     dom = prlsdkLoadDomain(driver, sdkdom, NULL);
1971 
1972     PrlHandle_Free(sdkdom);
1973     return dom;
1974 }
1975 
1976 virDomainObj *
prlsdkAddDomainByName(struct _vzDriver * driver,const char * name)1977 prlsdkAddDomainByName(struct _vzDriver *driver, const char *name)
1978 {
1979     PRL_HANDLE sdkdom;
1980     virDomainObj *dom;
1981 
1982     sdkdom = prlsdkSdkDomainLookupByName(driver, name);
1983     if (sdkdom == PRL_INVALID_HANDLE)
1984         return NULL;
1985 
1986     dom = prlsdkLoadDomain(driver, sdkdom, NULL);
1987 
1988     PrlHandle_Free(sdkdom);
1989     return dom;
1990 }
1991 
1992 int
prlsdkUpdateDomain(struct _vzDriver * driver,virDomainObj * dom)1993 prlsdkUpdateDomain(struct _vzDriver *driver, virDomainObj *dom)
1994 {
1995     PRL_HANDLE job;
1996     struct vzDomObj *pdom = dom->privateData;
1997 
1998     job = PrlVm_RefreshConfig(pdom->sdkdom);
1999     if (waitDomainJob(job, dom))
2000         return -1;
2001 
2002     return prlsdkLoadDomain(driver, pdom->sdkdom, dom) ? 0 : -1;
2003 }
2004 
2005 static void
prlsdkSendEvent(struct _vzDriver * driver,virDomainObj * dom,virDomainEventType lvEventType,int lvEventTypeDetails)2006 prlsdkSendEvent(struct _vzDriver *driver,
2007                 virDomainObj *dom,
2008                 virDomainEventType lvEventType,
2009                 int lvEventTypeDetails)
2010 {
2011     virObjectEvent *event;
2012 
2013     event = virDomainEventLifecycleNewFromObj(dom,
2014                                               lvEventType,
2015                                               lvEventTypeDetails);
2016     virObjectEventStateQueue(driver->domainEventState, event);
2017 }
2018 
2019 static void
prlsdkNewStateToEvent(VIRTUAL_MACHINE_STATE domainState,virDomainEventType * lvEventType,int * lvEventTypeDetails)2020 prlsdkNewStateToEvent(VIRTUAL_MACHINE_STATE domainState,
2021                       virDomainEventType *lvEventType,
2022                       int *lvEventTypeDetails)
2023 {
2024     /* We skip all intermediate states here, because
2025      * libvirt doesn't have corresponding event types for
2026      * them */
2027     switch ((int)domainState) {
2028     case VMS_STOPPED:
2029     case VMS_MOUNTED:
2030         *lvEventType = VIR_DOMAIN_EVENT_STOPPED;
2031         *lvEventTypeDetails = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
2032         break;
2033     case VMS_RUNNING:
2034         *lvEventType = VIR_DOMAIN_EVENT_STARTED;
2035         *lvEventTypeDetails = VIR_DOMAIN_EVENT_STARTED_BOOTED;
2036         break;
2037     case VMS_PAUSED:
2038         *lvEventType = VIR_DOMAIN_EVENT_SUSPENDED;
2039         *lvEventTypeDetails = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
2040         break;
2041     case VMS_SUSPENDED:
2042         *lvEventType = VIR_DOMAIN_EVENT_STOPPED;
2043         *lvEventTypeDetails = VIR_DOMAIN_EVENT_STOPPED_SAVED;
2044         break;
2045     default:
2046         VIR_DEBUG("Skip sending event about changing state to %X",
2047                   domainState);
2048         break;
2049     }
2050 }
2051 
2052 static void
prlsdkHandleVmStateEvent(struct _vzDriver * driver,PRL_HANDLE prlEvent,unsigned char * uuid)2053 prlsdkHandleVmStateEvent(struct _vzDriver *driver,
2054                          PRL_HANDLE prlEvent,
2055                          unsigned char *uuid)
2056 {
2057     PRL_RESULT pret = PRL_ERR_FAILURE;
2058     PRL_HANDLE eventParam = PRL_INVALID_HANDLE;
2059     PRL_INT32 domainState;
2060     virDomainObj *dom = NULL;
2061     struct vzDomObj *pdom;
2062     virDomainEventType lvEventType = 0;
2063     int lvEventTypeDetails = 0;
2064 
2065     dom = virDomainObjListFindByUUID(driver->domains, uuid);
2066     if (dom == NULL)
2067         return;
2068 
2069     pret = PrlEvent_GetParamByName(prlEvent, "vminfo_vm_state", &eventParam);
2070     prlsdkCheckRetGoto(pret, cleanup);
2071 
2072     pret = PrlEvtPrm_ToInt32(eventParam, &domainState);
2073     prlsdkCheckRetGoto(pret, cleanup);
2074 
2075     pdom = dom->privateData;
2076 
2077     prlsdkConvertDomainState(domainState, pdom->id, dom);
2078 
2079     prlsdkNewStateToEvent(domainState,
2080                           &lvEventType,
2081                           &lvEventTypeDetails);
2082 
2083     prlsdkSendEvent(driver, dom, lvEventType, lvEventTypeDetails);
2084 
2085  cleanup:
2086     PrlHandle_Free(eventParam);
2087     virDomainObjEndAPI(&dom);
2088     return;
2089 }
2090 
2091 static void
prlsdkHandleVmConfigEvent(struct _vzDriver * driver,unsigned char * uuid)2092 prlsdkHandleVmConfigEvent(struct _vzDriver *driver,
2093                           unsigned char *uuid)
2094 {
2095     virDomainObj *dom = NULL;
2096     bool job = false;
2097 
2098     dom = virDomainObjListFindByUUID(driver->domains, uuid);
2099     if (dom == NULL)
2100         return;
2101 
2102     if (vzDomainObjBeginJob(dom) < 0)
2103         goto cleanup;
2104     job = true;
2105 
2106     if (dom->removing)
2107         goto cleanup;
2108 
2109     if (prlsdkUpdateDomain(driver, dom) < 0)
2110         goto cleanup;
2111 
2112     prlsdkSendEvent(driver, dom, VIR_DOMAIN_EVENT_DEFINED,
2113                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
2114 
2115  cleanup:
2116     if (job)
2117         vzDomainObjEndJob(dom);
2118     virDomainObjEndAPI(&dom);
2119     return;
2120 }
2121 
2122 static void
prlsdkHandleVmAddedEvent(struct _vzDriver * driver,unsigned char * uuid)2123 prlsdkHandleVmAddedEvent(struct _vzDriver *driver,
2124                          unsigned char *uuid)
2125 {
2126     virDomainObj *dom = NULL;
2127 
2128     if (!(dom = virDomainObjListFindByUUID(driver->domains, uuid)) &&
2129         !(dom = prlsdkAddDomainByUUID(driver, uuid)))
2130         goto cleanup;
2131 
2132     prlsdkSendEvent(driver, dom, VIR_DOMAIN_EVENT_DEFINED,
2133                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
2134 
2135  cleanup:
2136     virDomainObjEndAPI(&dom);
2137     return;
2138 }
2139 
2140 static void
prlsdkHandleVmRemovedEvent(struct _vzDriver * driver,unsigned char * uuid)2141 prlsdkHandleVmRemovedEvent(struct _vzDriver *driver,
2142                            unsigned char *uuid)
2143 {
2144     virDomainObj *dom = NULL;
2145 
2146     dom = virDomainObjListFindByUUID(driver->domains, uuid);
2147     /* domain was removed from the list from the libvirt
2148      * API function in current connection */
2149     if (dom == NULL)
2150         return;
2151 
2152     prlsdkSendEvent(driver, dom, VIR_DOMAIN_EVENT_UNDEFINED,
2153                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
2154 
2155     virDomainObjListRemove(driver->domains, dom);
2156     virDomainObjEndAPI(&dom);
2157     return;
2158 }
2159 
2160 static void
prlsdkHandlePerfEvent(struct _vzDriver * driver,PRL_HANDLE event,unsigned char * uuid)2161 prlsdkHandlePerfEvent(struct _vzDriver *driver,
2162                       PRL_HANDLE event,
2163                       unsigned char *uuid)
2164 {
2165     virDomainObj *dom = NULL;
2166     struct vzDomObj *privdom = NULL;
2167 
2168     if (!(dom = virDomainObjListFindByUUID(driver->domains, uuid))) {
2169         PrlHandle_Free(event);
2170         return;
2171     }
2172 
2173     privdom = dom->privateData;
2174     PrlHandle_Free(privdom->stats);
2175     privdom->stats = event;
2176 
2177     virDomainObjEndAPI(&dom);
2178 }
2179 
2180 static void
prlsdkHandleMigrationProgress(struct _vzDriver * driver,PRL_HANDLE event,unsigned char * uuid)2181 prlsdkHandleMigrationProgress(struct _vzDriver *driver,
2182                               PRL_HANDLE event,
2183                               unsigned char *uuid)
2184 {
2185     virDomainObj *dom = NULL;
2186     struct vzDomObj *privdom = NULL;
2187     PRL_UINT32 progress;
2188     PRL_HANDLE param = PRL_INVALID_HANDLE;
2189     PRL_RESULT pret;
2190 
2191     if (!(dom = virDomainObjListFindByUUID(driver->domains, uuid)))
2192         return;
2193 
2194     pret = PrlEvent_GetParam(event, 0, &param);
2195     prlsdkCheckRetGoto(pret, cleanup);
2196 
2197     pret = PrlEvtPrm_ToUint32(param, &progress);
2198     prlsdkCheckRetGoto(pret, cleanup);
2199 
2200     privdom = dom->privateData;
2201     privdom->job.progress = progress;
2202 
2203  cleanup:
2204     PrlHandle_Free(param);
2205     virDomainObjEndAPI(&dom);
2206 }
2207 
2208 static PRL_RESULT
prlsdkEventsHandler(PRL_HANDLE prlEvent,PRL_VOID_PTR opaque)2209 prlsdkEventsHandler(PRL_HANDLE prlEvent, PRL_VOID_PTR opaque)
2210 {
2211     struct _vzDriver *driver = opaque;
2212     PRL_RESULT pret = PRL_ERR_FAILURE;
2213     PRL_HANDLE_TYPE handleType;
2214     char uuidstr[VIR_UUID_STRING_BRACED_BUFLEN];
2215     unsigned char uuid[VIR_UUID_BUFLEN];
2216     PRL_EVENT_TYPE prlEventType;
2217 
2218     pret = PrlHandle_GetType(prlEvent, &handleType);
2219     prlsdkCheckRetGoto(pret, cleanup);
2220 
2221     /* Currently, there is no need to handle anything but events */
2222     if (handleType != PHT_EVENT)
2223         goto cleanup;
2224 
2225     if (driver == NULL)
2226         goto cleanup;
2227 
2228     pret = prlsdkGetStringParamBuf(PrlEvent_GetIssuerId,
2229                                    prlEvent, uuidstr, sizeof(uuidstr));
2230     prlsdkCheckRetGoto(pret, cleanup);
2231 
2232     pret = PrlEvent_GetType(prlEvent, &prlEventType);
2233     prlsdkCheckRetGoto(pret, cleanup);
2234 
2235     if (prlsdkUUIDParse(uuidstr, uuid) < 0) {
2236         VIR_DEBUG("Skipping event type %d", prlEventType);
2237         goto cleanup;
2238     }
2239 
2240     switch ((int)prlEventType) {
2241     case PET_DSP_EVT_VM_STATE_CHANGED:
2242         prlsdkHandleVmStateEvent(driver, prlEvent, uuid);
2243         break;
2244     case PET_DSP_EVT_VM_CONFIG_CHANGED:
2245         prlsdkHandleVmConfigEvent(driver, uuid);
2246         break;
2247     case PET_DSP_EVT_VM_CREATED:
2248     case PET_DSP_EVT_VM_ADDED:
2249         prlsdkHandleVmAddedEvent(driver, uuid);
2250         break;
2251     case PET_DSP_EVT_VM_DELETED:
2252     case PET_DSP_EVT_VM_UNREGISTERED:
2253         prlsdkHandleVmRemovedEvent(driver, uuid);
2254         break;
2255     case PET_DSP_EVT_VM_PERFSTATS:
2256         prlsdkHandlePerfEvent(driver, prlEvent, uuid);
2257         /* above function takes own of event */
2258         prlEvent = PRL_INVALID_HANDLE;
2259         break;
2260     case PET_DSP_EVT_DISP_CONNECTION_CLOSED:
2261         vzDestroyDriverConnection();
2262         break;
2263     case PET_DSP_EVT_VM_MIGRATE_PROGRESS_CHANGED:
2264         prlsdkHandleMigrationProgress(driver, prlEvent, uuid);
2265         break;
2266     default:
2267         VIR_DEBUG("Skipping event of type %d", prlEventType);
2268     }
2269 
2270  cleanup:
2271     PrlHandle_Free(prlEvent);
2272     return PRL_ERR_SUCCESS;
2273 }
2274 
prlsdkStart(virDomainObj * dom)2275 int prlsdkStart(virDomainObj *dom)
2276 {
2277     PRL_HANDLE job = PRL_INVALID_HANDLE;
2278     struct vzDomObj *privdom = dom->privateData;
2279     PRL_RESULT pret;
2280 
2281     job = PrlVm_StartEx(privdom->sdkdom, PSM_VM_START, 0);
2282     if (PRL_FAILED(pret = waitDomainJob(job, dom))) {
2283         prlsdkConvertError(pret);
2284         return -1;
2285     }
2286 
2287     return 0;
2288 }
2289 
prlsdkKill(virDomainObj * dom)2290 int prlsdkKill(virDomainObj *dom)
2291 {
2292     PRL_HANDLE job = PRL_INVALID_HANDLE;
2293     struct vzDomObj *privdom = dom->privateData;
2294     PRL_RESULT pret;
2295 
2296     job = PrlVm_StopEx(privdom->sdkdom, PSM_KILL, 0);
2297     if (PRL_FAILED(pret = waitDomainJob(job, dom))) {
2298         prlsdkConvertError(pret);
2299         return -1;
2300     }
2301 
2302     return 0;
2303 }
2304 
prlsdkStop(virDomainObj * dom)2305 int prlsdkStop(virDomainObj *dom)
2306 {
2307     PRL_HANDLE job = PRL_INVALID_HANDLE;
2308     struct vzDomObj *privdom = dom->privateData;
2309     PRL_RESULT pret;
2310 
2311     job = PrlVm_StopEx(privdom->sdkdom, PSM_SHUTDOWN, 0);
2312     if (PRL_FAILED(pret = waitDomainJob(job, dom))) {
2313         prlsdkConvertError(pret);
2314         return -1;
2315     }
2316 
2317     return 0;
2318 }
2319 
prlsdkPause(virDomainObj * dom)2320 int prlsdkPause(virDomainObj *dom)
2321 {
2322     PRL_HANDLE job = PRL_INVALID_HANDLE;
2323     struct vzDomObj *privdom = dom->privateData;
2324     PRL_RESULT pret;
2325 
2326     job = PrlVm_Pause(privdom->sdkdom, false);
2327     if (PRL_FAILED(pret = waitDomainJob(job, dom))) {
2328         prlsdkConvertError(pret);
2329         return -1;
2330     }
2331 
2332     return 0;
2333 }
2334 
prlsdkResume(virDomainObj * dom)2335 int prlsdkResume(virDomainObj *dom)
2336 {
2337     PRL_HANDLE job = PRL_INVALID_HANDLE;
2338     struct vzDomObj *privdom = dom->privateData;
2339     PRL_RESULT pret;
2340 
2341     job = PrlVm_Resume(privdom->sdkdom);
2342     if (PRL_FAILED(pret = waitDomainJob(job, dom))) {
2343         prlsdkConvertError(pret);
2344         return -1;
2345     }
2346 
2347     return 0;
2348 }
2349 
prlsdkSuspend(virDomainObj * dom)2350 int prlsdkSuspend(virDomainObj *dom)
2351 {
2352     PRL_HANDLE job = PRL_INVALID_HANDLE;
2353     struct vzDomObj *privdom = dom->privateData;
2354     PRL_RESULT pret;
2355 
2356     job = PrlVm_Suspend(privdom->sdkdom);
2357     if (PRL_FAILED(pret = waitDomainJob(job, dom))) {
2358         prlsdkConvertError(pret);
2359         return -1;
2360     }
2361 
2362     return 0;
2363 }
2364 
prlsdkRestart(virDomainObj * dom)2365 int prlsdkRestart(virDomainObj *dom)
2366 {
2367     PRL_HANDLE job = PRL_INVALID_HANDLE;
2368     struct vzDomObj *privdom = dom->privateData;
2369     PRL_RESULT pret;
2370 
2371     job = PrlVm_Restart(privdom->sdkdom);
2372     if (PRL_FAILED(pret = waitDomainJob(job, dom))) {
2373         prlsdkConvertError(pret);
2374         return -1;
2375     }
2376 
2377     return 0;
2378 }
2379 
prlsdkReset(virDomainObj * dom)2380 int prlsdkReset(virDomainObj *dom)
2381 {
2382     PRL_HANDLE job = PRL_INVALID_HANDLE;
2383     struct vzDomObj *privdom = dom->privateData;
2384     PRL_RESULT pret;
2385 
2386     job = PrlVm_Reset(privdom->sdkdom);
2387     if (PRL_FAILED(pret = waitDomainJob(job, dom))) {
2388         prlsdkConvertError(pret);
2389         return -1;
2390     }
2391 
2392     return 0;
2393 }
2394 
2395 static void
prlsdkConvertError(PRL_RESULT pret)2396 prlsdkConvertError(PRL_RESULT pret)
2397 {
2398     virErrorNumber virerr;
2399 
2400     switch (pret) {
2401     case PRL_ERR_DISP_VM_IS_NOT_STARTED:
2402     case PRL_ERR_DISP_VM_IS_NOT_STOPPED:
2403     case PRL_ERR_INVALID_ACTION_REQUESTED:
2404     case PRL_ERR_UNIMPLEMENTED:
2405         virerr = VIR_ERR_OPERATION_INVALID;
2406         break;
2407     default:
2408         virerr = VIR_ERR_OPERATION_FAILED;
2409     }
2410 
2411     virResetLastError();
2412     virReportError(virerr, "%s", _("Can't change domain state."));
2413 }
2414 
2415 static int
prlsdkCheckUnsupportedParams(PRL_HANDLE sdkdom,virDomainDef * def)2416 prlsdkCheckUnsupportedParams(PRL_HANDLE sdkdom, virDomainDef *def)
2417 {
2418     size_t i;
2419     PRL_VM_TYPE vmType;
2420     PRL_RESULT pret;
2421     virDomainNumatuneMemMode memMode;
2422     int bus = IS_CT(def) ? VIR_DOMAIN_INPUT_BUS_PARALLELS :
2423                            VIR_DOMAIN_INPUT_BUS_PS2;
2424 
2425     if (def->title) {
2426         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2427                        _("titles are not supported by vz driver"));
2428         return -1;
2429     }
2430 
2431     if (def->blkio.ndevices > 0) {
2432         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2433                        _("blkio parameters are not supported "
2434                          "by vz driver"));
2435         return -1;
2436     }
2437 
2438     if (virDomainDefGetMemoryTotal(def) != def->mem.cur_balloon) {
2439         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2440                        _("changing balloon parameters is not supported "
2441                          "by vz driver"));
2442         return -1;
2443     }
2444 
2445     if (virDomainDefGetMemoryTotal(def) % (1 << 10) != 0) {
2446         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2447                        _("Memory size should be multiple of 1Mb."));
2448         return -1;
2449     }
2450 
2451     if (def->mem.nhugepages ||
2452         virMemoryLimitIsSet(def->mem.hard_limit) ||
2453         virMemoryLimitIsSet(def->mem.soft_limit) ||
2454         def->mem.min_guarantee ||
2455         virMemoryLimitIsSet(def->mem.swap_hard_limit)) {
2456 
2457         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2458                        _("Memory parameter is not supported "
2459                          "by vz driver"));
2460         return -1;
2461     }
2462 
2463     if (virDomainDefHasVcpusOffline(def)) {
2464         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2465                        _("current vcpus must be equal to maxvcpus"));
2466         return -1;
2467     }
2468 
2469     if (def->placement_mode) {
2470         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2471                        _("changing cpu placement mode is not supported "
2472                          "by vz driver"));
2473         return -1;
2474     }
2475 
2476     if (def->cputune.shares ||
2477         def->cputune.sharesSpecified ||
2478         def->cputune.period ||
2479         def->cputune.quota) {
2480 
2481         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2482                        _("cputune is not supported by vz driver"));
2483         return -1;
2484     }
2485 
2486     for (i = 0; i < virDomainDefGetVcpusMax(def); i++) {
2487         virDomainVcpuDef *vcpu = virDomainDefGetVcpu(def, i);
2488 
2489         if (vcpu->cpumask &&
2490             !virBitmapEqual(def->cpumask, vcpu->cpumask)) {
2491             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2492                            _("vcpupin cpumask differs from default cpumask"));
2493             return -1;
2494         }
2495     }
2496 
2497 
2498     /*
2499      * Though we don't support NUMA configuration at the moment
2500      * virDomainDef *always contain non zero NUMA configuration
2501      * So, just make sure this configuration doesn't differ from auto generated.
2502      */
2503     if ((virDomainNumatuneGetMode(def->numa, -1, &memMode) == 0 &&
2504          memMode == VIR_DOMAIN_NUMATUNE_MEM_STRICT) ||
2505         virDomainNumatuneHasPerNodeBinding(def->numa)) {
2506         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2507                        _("numa parameters are not supported "
2508                          "by vz driver"));
2509         return -1;
2510     }
2511 
2512     if (def->onReboot != VIR_DOMAIN_LIFECYCLE_ACTION_RESTART ||
2513         def->onPoweroff != VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY ||
2514         def->onCrash != VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY) {
2515 
2516         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2517                        _("on_reboot, on_poweroff and on_crash parameters "
2518                          "are not supported by vz driver"));
2519         return -1;
2520     }
2521 
2522     /* we fill only type and arch fields in vzLoadDomain for
2523      * hvm type and also init for containers, so we can check that all
2524      * other parameters are null and boot devices config is default */
2525 
2526     if (def->os.machine != NULL || def->os.bootmenu != 0 ||
2527         def->os.kernel != NULL || def->os.initrd != NULL ||
2528         def->os.cmdline != NULL || def->os.root != NULL ||
2529         def->os.loader != NULL || def->os.bootloader != NULL ||
2530         def->os.bootloaderArgs != NULL || def->os.smbios_mode != 0 ||
2531         def->os.bios.useserial != 0) {
2532 
2533         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2534                        _("changing OS parameters is not supported "
2535                          "by vz driver"));
2536         return -1;
2537     }
2538 
2539     pret = PrlVmCfg_GetVmType(sdkdom, &vmType);
2540     if (PRL_FAILED(pret)) {
2541         logPrlError(pret);
2542         return -1;
2543     }
2544 
2545     if (!(vmType == PVT_VM && !IS_CT(def)) &&
2546         !(vmType == PVT_CT && IS_CT(def))) {
2547 
2548         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2549                        _("changing OS type is not supported "
2550                          "by vz driver"));
2551         return -1;
2552     }
2553 
2554     if (!IS_CT(def)) {
2555         if (def->os.init != NULL || def->os.initargv != NULL) {
2556             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2557                            _("unsupported OS parameters"));
2558             return -1;
2559         }
2560     } else {
2561         if (def->os.nBootDevs != 0 ||
2562             STRNEQ_NULLABLE(def->os.init, "/sbin/init") ||
2563             (def->os.initargv != NULL && def->os.initargv[0] != NULL)) {
2564 
2565             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2566                            _("unsupported OS parameters"));
2567             return -1;
2568         }
2569     }
2570 
2571     if (def->emulator) {
2572         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2573                        _("changing emulator is not supported "
2574                          "by vz driver"));
2575         return -1;
2576     }
2577 
2578     for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) {
2579         if (def->features[i]) {
2580             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2581                            _("changing features is not supported "
2582                              "by vz driver"));
2583             return -1;
2584         }
2585     }
2586 
2587     if (def->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_UTC ||
2588         def->clock.ntimers != 0) {
2589 
2590         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2591                        _("changing clock parameters is not supported "
2592                          "by vz driver"));
2593         return -1;
2594     }
2595 
2596     if (!IS_CT(def) && def->nfss != 0) {
2597         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2598                        _("Filesystems in VMs are not supported "
2599                          "by vz driver"));
2600         return -1;
2601     }
2602 
2603     if (def->nsounds != 0 || def->nhostdevs != 0 ||
2604         def->nredirdevs != 0 || def->nsmartcards != 0 ||
2605         def->nparallels || def->nchannels != 0 ||
2606         def->nleases != 0 || def->nhubs != 0) {
2607 
2608         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2609                        _("changing devices parameters is not supported "
2610                          "by vz driver"));
2611         return -1;
2612     }
2613 
2614     /* check we have only default input devices */
2615     if (def->ngraphics > 0) {
2616         if (def->ninputs != 2 ||
2617             def->inputs[0]->bus != bus ||
2618             def->inputs[1]->bus != bus ||
2619             !((def->inputs[0]->type == VIR_DOMAIN_INPUT_TYPE_MOUSE &&
2620                def->inputs[1]->type == VIR_DOMAIN_INPUT_TYPE_KBD) ||
2621               (def->inputs[0]->type == VIR_DOMAIN_INPUT_TYPE_KBD &&
2622                def->inputs[1]->type == VIR_DOMAIN_INPUT_TYPE_MOUSE))) {
2623 
2624             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2625                            _("unsupported input device configuration"));
2626             return -1;
2627         }
2628     } else if (def->ninputs != 0) {
2629         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2630                        _("input devices without vnc are not supported"));
2631         return -1;
2632     }
2633 
2634     return 0;
2635 }
2636 
prlsdkClearDevices(PRL_HANDLE sdkdom)2637 static int prlsdkClearDevices(PRL_HANDLE sdkdom)
2638 {
2639     PRL_RESULT pret;
2640     PRL_UINT32 n, i;
2641     PRL_HANDLE devList;
2642     PRL_HANDLE dev;
2643     int ret = -1;
2644 
2645     pret = PrlVmCfg_GetAllDevices(sdkdom, &devList);
2646     prlsdkCheckRetGoto(pret, cleanup);
2647 
2648     pret = PrlHndlList_GetItemsCount(devList, &n);
2649     prlsdkCheckRetGoto(pret, cleanup);
2650 
2651     for (i = 0; i < n; i++) {
2652         pret = PrlHndlList_GetItem(devList, i, &dev);
2653         prlsdkCheckRetGoto(pret, cleanup);
2654 
2655         pret = PrlVmDev_Remove(dev);
2656         PrlHandle_Free(dev);
2657     }
2658 
2659     ret = 0;
2660  cleanup:
2661     PrlHandle_Free(devList);
2662     return ret;
2663 }
2664 
2665 static int
prlsdkRemoveBootDevices(PRL_HANDLE sdkdom)2666 prlsdkRemoveBootDevices(PRL_HANDLE sdkdom)
2667 {
2668     PRL_RESULT pret;
2669     PRL_UINT32 i, devCount;
2670     PRL_HANDLE dev = PRL_INVALID_HANDLE;
2671     PRL_DEVICE_TYPE devType;
2672 
2673     pret = PrlVmCfg_GetBootDevCount(sdkdom, &devCount);
2674     prlsdkCheckRetExit(pret, -1);
2675 
2676     for (i = 0; i < devCount; i++) {
2677 
2678         /* always get device by index 0, because device list resort after delete */
2679         pret = PrlVmCfg_GetBootDev(sdkdom, 0, &dev);
2680         prlsdkCheckRetExit(pret, -1);
2681 
2682         pret = PrlBootDev_GetType(dev, &devType);
2683         prlsdkCheckRetExit(pret, -1);
2684 
2685         pret = PrlBootDev_Remove(dev);
2686         prlsdkCheckRetExit(pret, -1);
2687     }
2688 
2689     return 0;
2690 }
2691 
2692 static int
prlsdkAddDeviceToBootList(PRL_HANDLE sdkdom,PRL_UINT32 devIndex,PRL_DEVICE_TYPE devType,PRL_UINT32 bootSequence)2693 prlsdkAddDeviceToBootList(PRL_HANDLE sdkdom,
2694                           PRL_UINT32 devIndex,
2695                           PRL_DEVICE_TYPE devType,
2696                           PRL_UINT32 bootSequence)
2697 {
2698     PRL_RESULT pret;
2699     PRL_HANDLE bootDev = PRL_INVALID_HANDLE;
2700 
2701     pret = PrlVmCfg_CreateBootDev(sdkdom, &bootDev);
2702     prlsdkCheckRetGoto(pret, error);
2703 
2704     pret = PrlBootDev_SetIndex(bootDev, devIndex);
2705     prlsdkCheckRetGoto(pret, error);
2706 
2707     pret = PrlBootDev_SetType(bootDev, devType);
2708     prlsdkCheckRetGoto(pret, error);
2709 
2710     pret = PrlBootDev_SetSequenceIndex(bootDev, bootSequence);
2711     prlsdkCheckRetGoto(pret, error);
2712 
2713     pret = PrlBootDev_SetInUse(bootDev, PRL_TRUE);
2714     prlsdkCheckRetGoto(pret, error);
2715 
2716     return 0;
2717 
2718  error:
2719     if (bootDev != PRL_INVALID_HANDLE)
2720         PrlBootDev_Remove(bootDev);
2721 
2722     return -1;
2723 }
2724 
prlsdkCheckVideoUnsupportedParams(virDomainDef * def)2725 static int prlsdkCheckVideoUnsupportedParams(virDomainDef *def)
2726 {
2727     virDomainVideoDef *v;
2728 
2729     if (IS_CT(def)) {
2730         if (def->nvideos == 0) {
2731             return 0;
2732         } else {
2733             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2734                            _("Video adapters are not supported "
2735                              "int containers."));
2736             return -1;
2737         }
2738     } else {
2739         if (def->nvideos != 1) {
2740             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2741                            _("vz driver supports "
2742                              "only one video adapter."));
2743             return -1;
2744         }
2745     }
2746 
2747     v = def->videos[0];
2748 
2749     if (v->type != VIR_DOMAIN_VIDEO_TYPE_VGA) {
2750         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2751                        _("vz driver supports "
2752                          "only VGA video adapters."));
2753         return -1;
2754     }
2755 
2756     if (v->heads != 1) {
2757         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2758                        _("vz driver doesn't support "
2759                          "multihead video adapters."));
2760         return -1;
2761     }
2762 
2763     if (v->accel != NULL && (v->accel->accel2d || v->accel->accel3d)) {
2764         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2765                        _("vz driver doesn't support "
2766                          "setting video acceleration parameters."));
2767         return -1;
2768     }
2769 
2770     return 0;
2771 }
2772 
prlsdkCheckSerialUnsupportedParams(virDomainChrDef * chr)2773 static int prlsdkCheckSerialUnsupportedParams(virDomainChrDef *chr)
2774 {
2775     if (chr->deviceType != VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL) {
2776         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2777                        _("Specified character device type is not supported "
2778                          "by vz driver."));
2779         return -1;
2780     }
2781 
2782     if (chr->targetType != VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_NONE) {
2783         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2784                        _("Specified character device target type is not "
2785                          "supported by vz driver."));
2786         return -1;
2787     }
2788 
2789     if (chr->source->type != VIR_DOMAIN_CHR_TYPE_DEV &&
2790         chr->source->type != VIR_DOMAIN_CHR_TYPE_FILE &&
2791         chr->source->type != VIR_DOMAIN_CHR_TYPE_UNIX &&
2792         chr->source->type != VIR_DOMAIN_CHR_TYPE_TCP &&
2793         chr->source->type != VIR_DOMAIN_CHR_TYPE_UDP) {
2794 
2795 
2796         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2797                        _("Specified character device source type is not "
2798                          "supported by vz driver."));
2799         return -1;
2800     }
2801 
2802     if (chr->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
2803         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2804                        _("Setting device info for character devices is not "
2805                          "supported by vz driver."));
2806         return -1;
2807     }
2808 
2809     if (chr->source->nseclabels > 0) {
2810         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2811                        _("Setting security labels is not "
2812                          "supported by vz driver."));
2813         return -1;
2814     }
2815 
2816    if (chr->source->type == VIR_DOMAIN_CHR_TYPE_TCP &&
2817         chr->source->data.tcp.protocol != VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW) {
2818         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2819                        _("Protocol '%s' is not supported for "
2820                          "tcp character device."),
2821                        virDomainChrTcpProtocolTypeToString(chr->source->data.tcp.protocol));
2822         return -1;
2823     }
2824 
2825     if (chr->source->type == VIR_DOMAIN_CHR_TYPE_UDP &&
2826         (STRNEQ(chr->source->data.udp.bindHost,
2827                 chr->source->data.udp.connectHost) ||
2828          STRNEQ(chr->source->data.udp.bindService,
2829                 chr->source->data.udp.connectService))) {
2830         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2831                        _("Different bind and connect parameters for "
2832                          "udp character device is not supported."));
2833         return -1;
2834     }
2835 
2836     return 0;
2837 }
2838 
prlsdkCheckNetUnsupportedParams(virDomainNetDef * net)2839 static int prlsdkCheckNetUnsupportedParams(virDomainNetDef *net)
2840 {
2841     if (net->type != VIR_DOMAIN_NET_TYPE_NETWORK &&
2842         net->type != VIR_DOMAIN_NET_TYPE_BRIDGE) {
2843         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2844                        _("Specified network adapter type is not "
2845                          "supported by vz driver."));
2846         return -1;
2847     }
2848 
2849     if (net->backend.tap || net->backend.vhost) {
2850         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2851                        _("Interface backend parameters are not "
2852                          "supported by vz driver."));
2853         return -1;
2854     }
2855 
2856     if (net->data.network.portgroup) {
2857         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2858                        _("Virtual network portgroups are not "
2859                          "supported by vz driver."));
2860         return -1;
2861     }
2862 
2863     if (net->tune.sndbuf_specified) {
2864         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2865                        _("Setting interface sndbuf is not "
2866                          "supported by vz driver."));
2867         return -1;
2868     }
2869 
2870     if (net->script) {
2871         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2872                        _("Setting interface script is not "
2873                          "supported by vz driver."));
2874         return -1;
2875     }
2876 
2877     if (net->ifname_guest) {
2878         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2879                        _("Setting guest interface name is not "
2880                          "supported by vz driver."));
2881         return -1;
2882     }
2883 
2884     if (net->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
2885         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2886                        _("Setting device info for network devices is not "
2887                          "supported by vz driver."));
2888         return -1;
2889     }
2890 
2891     if (net->filter) {
2892         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2893                        _("Setting network filter is not "
2894                          "supported by vz driver."));
2895         return -1;
2896     }
2897 
2898     if (net->bandwidth) {
2899         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2900                        _("Setting network bandwidth is not "
2901                          "supported by vz driver."));
2902         return -1;
2903     }
2904 
2905     if (net->vlan.trunk) {
2906         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2907                        _("Setting up vlans is not "
2908                          "supported by vz driver."));
2909         return -1;
2910     }
2911 
2912     return 0;
2913 }
2914 
prlsdkCheckFSUnsupportedParams(virDomainFSDef * fs)2915 static int prlsdkCheckFSUnsupportedParams(virDomainFSDef *fs)
2916 {
2917     if (fs->type != VIR_DOMAIN_FS_TYPE_FILE &&
2918         fs->type != VIR_DOMAIN_FS_TYPE_VOLUME) {
2919         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2920                        _("Only file based or volume based filesystems "
2921                          "are supported by vz driver."));
2922         return -1;
2923     }
2924 
2925     if (fs->fsdriver != VIR_DOMAIN_FS_DRIVER_TYPE_PLOOP) {
2926         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2927                        _("Only ploop fs driver is "
2928                          "supported by vz driver."));
2929         return -1;
2930     }
2931 
2932     if (fs->accessmode != VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) {
2933         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2934                        _("Changing fs access mode is not "
2935                          "supported by vz driver."));
2936         return -1;
2937     }
2938 
2939     if (fs->wrpolicy != VIR_DOMAIN_FS_WRPOLICY_DEFAULT) {
2940         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2941                        _("Changing fs write policy is not "
2942                          "supported by vz driver."));
2943         return -1;
2944     }
2945 
2946     if (fs->format != VIR_STORAGE_FILE_PLOOP) {
2947         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2948                        _("Only ploop disk images are "
2949                          "supported by vz driver."));
2950         return -1;
2951     }
2952 
2953     if (fs->readonly) {
2954         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2955                        _("Setting readonly for filesystems is "
2956                          "not supported by vz driver."));
2957         return -1;
2958     }
2959 
2960     if (fs->space_hard_limit || fs->space_soft_limit) {
2961         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2962                        _("Setting fs quotas is not "
2963                          "supported by vz driver."));
2964         return -1;
2965     }
2966 
2967     return 0;
2968 }
2969 
prlsdkApplyGraphicsParams(PRL_HANDLE sdkdom,virDomainGraphicsDef * gr)2970 static int prlsdkApplyGraphicsParams(PRL_HANDLE sdkdom,
2971                                      virDomainGraphicsDef *gr)
2972 {
2973     virDomainGraphicsListenDef *glisten;
2974     PRL_RESULT pret;
2975 
2976     if (!gr) {
2977         pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_DISABLED);
2978         prlsdkCheckRetExit(pret, -1);
2979         return 0;
2980     }
2981 
2982     pret = PrlVmCfg_SetVNCPassword(sdkdom, gr->data.vnc.auth.passwd ? : "");
2983     prlsdkCheckRetExit(pret, -1);
2984 
2985     if (gr->data.vnc.autoport) {
2986         pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_AUTO);
2987         prlsdkCheckRetExit(pret, -1);
2988     } else {
2989         pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_MANUAL);
2990         prlsdkCheckRetExit(pret, -1);
2991 
2992         pret = PrlVmCfg_SetVNCPort(sdkdom, gr->data.vnc.port);
2993         prlsdkCheckRetExit(pret, -1);
2994     }
2995 
2996     glisten = virDomainGraphicsGetListen(gr, 0);
2997     pret = PrlVmCfg_SetVNCHostName(sdkdom, glisten && glisten->address ?
2998                                            glisten->address : VIR_LOOPBACK_IPV4_ADDR);
2999     prlsdkCheckRetExit(pret, -1);
3000 
3001     return 0;
3002 }
3003 
prlsdkApplyVideoParams(PRL_HANDLE sdkdom G_GNUC_UNUSED,virDomainDef * def)3004 static int prlsdkApplyVideoParams(PRL_HANDLE sdkdom G_GNUC_UNUSED, virDomainDef *def)
3005 {
3006     PRL_RESULT pret;
3007 
3008     if (def->nvideos == 0)
3009         return 0;
3010 
3011     if (IS_CT(def)) {
3012         /* ignore video parameters */
3013         return 0;
3014     }
3015 
3016     if (prlsdkCheckVideoUnsupportedParams(def))
3017         return -1;
3018 
3019     pret = PrlVmCfg_SetVideoRamSize(sdkdom, def->videos[0]->vram >> 10);
3020     prlsdkCheckRetExit(pret, -1);
3021 
3022     return 0;
3023 }
3024 
prlsdkAddSerial(PRL_HANDLE sdkdom,virDomainChrDef * chr)3025 static int prlsdkAddSerial(PRL_HANDLE sdkdom, virDomainChrDef *chr)
3026 {
3027     PRL_RESULT pret;
3028     PRL_HANDLE sdkchr = PRL_INVALID_HANDLE;
3029     PRL_VM_DEV_EMULATION_TYPE emutype;
3030     PRL_SERIAL_PORT_SOCKET_OPERATION_MODE socket_mode = PSP_SERIAL_SOCKET_SERVER;
3031     char *path;
3032     char *url = NULL;
3033     int ret = -1;
3034 
3035     if (prlsdkCheckSerialUnsupportedParams(chr) < 0)
3036         return -1;
3037 
3038     pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_SERIAL_PORT, &sdkchr);
3039     prlsdkCheckRetGoto(pret, cleanup);
3040 
3041     switch (chr->source->type) {
3042     case VIR_DOMAIN_CHR_TYPE_DEV:
3043         emutype = PDT_USE_REAL_DEVICE;
3044         path = chr->source->data.file.path;
3045         break;
3046     case VIR_DOMAIN_CHR_TYPE_FILE:
3047         emutype = PDT_USE_OUTPUT_FILE;
3048         path = chr->source->data.file.path;
3049         break;
3050     case VIR_DOMAIN_CHR_TYPE_UNIX:
3051         emutype = PDT_USE_SERIAL_PORT_SOCKET_MODE;
3052         path = chr->source->data.nix.path;
3053         if (!chr->source->data.nix.listen)
3054             socket_mode = PSP_SERIAL_SOCKET_CLIENT;
3055         break;
3056     case VIR_DOMAIN_CHR_TYPE_TCP:
3057         emutype = PDT_USE_TCP;
3058         url = g_strdup_printf("%s:%s", chr->source->data.tcp.host,
3059                               chr->source->data.tcp.service);
3060         if (!chr->source->data.tcp.listen)
3061             socket_mode = PSP_SERIAL_SOCKET_CLIENT;
3062         path = url;
3063         break;
3064     case VIR_DOMAIN_CHR_TYPE_UDP:
3065         emutype = PDT_USE_UDP;
3066         url = g_strdup_printf("%s:%s", chr->source->data.udp.bindHost,
3067                               chr->source->data.udp.bindService);
3068         path = url;
3069         break;
3070     default:
3071         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3072                        _("vz driver doesn't support "
3073                          "specified serial source type."));
3074         goto cleanup;
3075     }
3076 
3077     pret = PrlVmDev_SetEmulatedType(sdkchr, emutype);
3078     prlsdkCheckRetGoto(pret, cleanup);
3079 
3080     pret = PrlVmDev_SetSysName(sdkchr, path);
3081     prlsdkCheckRetGoto(pret, cleanup);
3082 
3083     pret = PrlVmDev_SetFriendlyName(sdkchr, path);
3084     prlsdkCheckRetGoto(pret, cleanup);
3085 
3086     pret = PrlVmDevSerial_SetSocketMode(sdkchr, socket_mode);
3087     prlsdkCheckRetGoto(pret, cleanup);
3088 
3089     pret = PrlVmDev_SetEnabled(sdkchr, 1);
3090     prlsdkCheckRetGoto(pret, cleanup);
3091 
3092     pret = PrlVmDev_SetIndex(sdkchr, chr->target.port);
3093     prlsdkCheckRetGoto(pret, cleanup);
3094 
3095     ret = 0;
3096  cleanup:
3097     PrlHandle_Free(sdkchr);
3098     VIR_FREE(url);
3099     return ret;
3100 }
3101 
3102 #define PRL_MAC_STRING_BUFNAME  13
3103 
prlsdkFormatMac(virMacAddr * mac,char * macstr)3104 static const char * prlsdkFormatMac(virMacAddr *mac, char *macstr)
3105 {
3106     g_snprintf(macstr, PRL_MAC_STRING_BUFNAME,
3107                "%02X%02X%02X%02X%02X%02X",
3108                mac->addr[0], mac->addr[1], mac->addr[2],
3109                mac->addr[3], mac->addr[4], mac->addr[5]);
3110     macstr[PRL_MAC_STRING_BUFNAME - 1] = '\0';
3111     return macstr;
3112 }
3113 
prlsdkConfigureGateways(PRL_HANDLE sdknet,virDomainNetDef * net)3114 static int prlsdkConfigureGateways(PRL_HANDLE sdknet, virDomainNetDef *net)
3115 {
3116     int ret = -1;
3117     size_t i;
3118     virNetDevIPRoute *route4 = NULL;
3119     virNetDevIPRoute *route6 = NULL;
3120     char *gw4 = NULL, *gw6 = NULL;
3121     PRL_RESULT pret;
3122 
3123     for (i = 0; i < net->guestIP.nroutes; i++) {
3124         virSocketAddr *addrdst;
3125         virSocketAddr *gateway;
3126         virSocketAddr zero;
3127 
3128         addrdst = virNetDevIPRouteGetAddress(net->guestIP.routes[i]);
3129         gateway = virNetDevIPRouteGetGateway(net->guestIP.routes[i]);
3130 
3131         ignore_value(virSocketAddrParse(&zero,
3132                                 (VIR_SOCKET_ADDR_IS_FAMILY(addrdst, AF_INET)
3133                                  ? VIR_SOCKET_ADDR_IPV4_ALL
3134                                  : VIR_SOCKET_ADDR_IPV6_ALL),
3135                                 VIR_SOCKET_ADDR_FAMILY(addrdst)));
3136         /* virSocketAddrParse raises an error
3137          * and we are not going to report it, reset it explicitly */
3138         virResetLastError();
3139 
3140         if (!virSocketAddrEqual(addrdst, &zero)) {
3141             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3142                            _("Support only default gateway"));
3143             return -1;
3144         }
3145 
3146         switch (VIR_SOCKET_ADDR_FAMILY(gateway)) {
3147         case AF_INET:
3148             if (route4) {
3149                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3150                                _("Support only one IPv4 default gateway"));
3151                 return -1;
3152             }
3153 
3154             route4 = net->guestIP.routes[i];
3155 
3156             break;
3157         case AF_INET6:
3158             if (route6) {
3159                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3160                                _("Support only one IPv6 default gateway"));
3161                 return -1;
3162             }
3163 
3164             route6 = net->guestIP.routes[i];
3165 
3166             break;
3167         default:
3168             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3169                            _("Unsupported address family %d "
3170                              "Only IPv4 or IPv6 default gateway"),
3171                            VIR_SOCKET_ADDR_FAMILY(gateway));
3172 
3173             return -1;
3174         }
3175     }
3176 
3177     if (route4 &&
3178         !(gw4 = virSocketAddrFormat(virNetDevIPRouteGetGateway(route4))))
3179         goto cleanup;
3180 
3181     pret = PrlVmDevNet_SetDefaultGateway(sdknet, gw4 ? : "");
3182     prlsdkCheckRetGoto(pret, cleanup);
3183 
3184     if (route6 &&
3185         !(gw6 = virSocketAddrFormat(virNetDevIPRouteGetGateway(route6))))
3186         goto cleanup;
3187 
3188     pret = PrlVmDevNet_SetDefaultGatewayIPv6(sdknet, gw6 ? : "");
3189     prlsdkCheckRetGoto(pret, cleanup);
3190 
3191     ret = 0;
3192 
3193  cleanup:
3194     VIR_FREE(gw4);
3195     VIR_FREE(gw6);
3196 
3197     return ret;
3198 }
3199 
prlsdkConfigureNet(struct _vzDriver * driver G_GNUC_UNUSED,virDomainObj * dom G_GNUC_UNUSED,PRL_HANDLE sdkdom,virDomainNetDef * net,bool isCt,bool create)3200 static int prlsdkConfigureNet(struct _vzDriver *driver G_GNUC_UNUSED,
3201                               virDomainObj *dom G_GNUC_UNUSED,
3202                               PRL_HANDLE sdkdom,
3203                               virDomainNetDef *net,
3204                               bool isCt, bool create)
3205 {
3206     PRL_RESULT pret;
3207     PRL_HANDLE sdknet = PRL_INVALID_HANDLE;
3208     PRL_HANDLE addrlist = PRL_INVALID_HANDLE;
3209     size_t i;
3210     int ret = -1;
3211     char macstr[PRL_MAC_STRING_BUFNAME];
3212     char *addrstr = NULL;
3213     bool ipv6present = false;
3214     bool ipv4present = false;
3215 
3216     if (prlsdkCheckNetUnsupportedParams(net) < 0)
3217         return -1;
3218 
3219     if (create) {
3220         pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_GENERIC_NETWORK_ADAPTER, &sdknet);
3221         prlsdkCheckRetGoto(pret, cleanup);
3222     } else {
3223         sdknet = prlsdkFindNetByMAC(sdkdom, &net->mac);
3224         if (sdknet == PRL_INVALID_HANDLE)
3225             return -1;
3226     }
3227 
3228     pret = PrlVmDev_SetEnabled(sdknet, 1);
3229     prlsdkCheckRetGoto(pret, cleanup);
3230 
3231     pret = PrlVmDev_SetConnected(sdknet, net->linkstate !=
3232                                  VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN);
3233 
3234     prlsdkCheckRetGoto(pret, cleanup);
3235 
3236     if (net->ifname) {
3237         pret = PrlVmDevNet_SetHostInterfaceName(sdknet, net->ifname);
3238         prlsdkCheckRetGoto(pret, cleanup);
3239     }
3240 
3241     prlsdkFormatMac(&net->mac, macstr);
3242     pret = PrlVmDevNet_SetMacAddress(sdknet, macstr);
3243     prlsdkCheckRetGoto(pret, cleanup);
3244 
3245     pret = PrlApi_CreateStringsList(&addrlist);
3246     prlsdkCheckRetGoto(pret, cleanup);
3247 
3248     for (i = 0; i < net->guestIP.nips; i++) {
3249         char *tmpstr;
3250 
3251         if (AF_INET == VIR_SOCKET_ADDR_FAMILY(&net->guestIP.ips[i]->address))
3252             ipv4present = true;
3253         else if (AF_INET6 == VIR_SOCKET_ADDR_FAMILY(&net->guestIP.ips[i]->address))
3254             ipv6present = true;
3255         else
3256             continue;
3257 
3258         if (!(tmpstr = virSocketAddrFormat(&net->guestIP.ips[i]->address)))
3259             goto cleanup;
3260 
3261         addrstr = g_strdup_printf("%s/%d", tmpstr, net->guestIP.ips[i]->prefix);
3262 
3263         VIR_FREE(tmpstr);
3264         pret = PrlStrList_AddItem(addrlist, addrstr);
3265         prlsdkCheckRetGoto(pret, cleanup);
3266 
3267         VIR_FREE(addrstr);
3268     }
3269 
3270     if (ipv4present || ipv6present) {
3271         pret = PrlVmDevNet_SetNetAddresses(sdknet, addrlist);
3272         prlsdkCheckRetGoto(pret, cleanup);
3273     }
3274 
3275     pret = PrlVmDevNet_SetConfigureWithDhcp(sdknet, !ipv4present);
3276     prlsdkCheckRetGoto(pret, cleanup);
3277 
3278     pret = PrlVmDevNet_SetConfigureWithDhcpIPv6(sdknet, !ipv6present);
3279     prlsdkCheckRetGoto(pret, cleanup);
3280 
3281     pret = PrlVmDevNet_SetAutoApply(sdknet, true);
3282     prlsdkCheckRetGoto(pret, cleanup);
3283 
3284     if (prlsdkConfigureGateways(sdknet, net))
3285         goto cleanup;
3286 
3287     if (isCt) {
3288         if (net->model != VIR_DOMAIN_NET_MODEL_UNKNOWN)
3289             VIR_WARN("Setting network adapter for containers is not "
3290                      "supported by vz driver.");
3291     } else {
3292         if (net->model == VIR_DOMAIN_NET_MODEL_RTL8139) {
3293             pret = PrlVmDevNet_SetAdapterType(sdknet, PNT_RTL);
3294         } else if (net->model == VIR_DOMAIN_NET_MODEL_E1000) {
3295             pret = PrlVmDevNet_SetAdapterType(sdknet, PNT_E1000);
3296         } else if (net->model == VIR_DOMAIN_NET_MODEL_VIRTIO) {
3297             pret = PrlVmDevNet_SetAdapterType(sdknet, PNT_VIRTIO);
3298         } else {
3299             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3300                            _("Specified network adapter model is not "
3301                              "supported by vz driver."));
3302             goto cleanup;
3303         }
3304         prlsdkCheckRetGoto(pret, cleanup);
3305     }
3306 
3307     if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
3308         if (STREQ(net->data.network.name, PARALLELS_DOMAIN_ROUTED_NETWORK_NAME)) {
3309             pret = PrlVmDev_SetEmulatedType(sdknet, PNA_ROUTED);
3310             prlsdkCheckRetGoto(pret, cleanup);
3311         } else {
3312             pret = PrlVmDev_SetEmulatedType(sdknet, PNA_BRIDGED_NETWORK);
3313             prlsdkCheckRetGoto(pret, cleanup);
3314 
3315             pret = PrlVmDevNet_SetVirtualNetworkId(sdknet, net->data.network.name);
3316             prlsdkCheckRetGoto(pret, cleanup);
3317         }
3318 
3319     } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
3320 
3321         pret = PrlVmDev_SetEmulatedType(sdknet, PNA_BRIDGE);
3322         prlsdkCheckRetGoto(pret, cleanup);
3323 
3324         pret = PrlVmDevNet_SetVirtualNetworkId(sdknet, net->data.bridge.brname);
3325         prlsdkCheckRetGoto(pret, cleanup);
3326     }
3327 
3328     pret = PrlVmDevNet_SetPktFilterPreventMacSpoof(sdknet,
3329                 net->trustGuestRxFilters == VIR_TRISTATE_BOOL_YES);
3330     prlsdkCheckRetGoto(pret, cleanup);
3331 
3332     ret = 0;
3333  cleanup:
3334     VIR_FREE(addrstr);
3335     PrlHandle_Free(addrlist);
3336     PrlHandle_Free(sdknet);
3337     return ret;
3338 }
3339 
3340 static PRL_HANDLE
prlsdkFindNetByMAC(PRL_HANDLE sdkdom,virMacAddr * mac)3341 prlsdkFindNetByMAC(PRL_HANDLE sdkdom, virMacAddr *mac)
3342 {
3343     PRL_RESULT pret;
3344     PRL_UINT32 adaptersCount;
3345     PRL_UINT32 i;
3346     PRL_HANDLE adapter = PRL_INVALID_HANDLE;
3347     char adapterMac[PRL_MAC_STRING_BUFNAME];
3348     char expectedMac[PRL_MAC_STRING_BUFNAME];
3349     char virMac[VIR_MAC_STRING_BUFLEN];
3350 
3351     prlsdkFormatMac(mac, expectedMac);
3352 
3353     pret = PrlVmCfg_GetNetAdaptersCount(sdkdom, &adaptersCount);
3354     prlsdkCheckRetGoto(pret, cleanup);
3355 
3356     for (i = 0; i < adaptersCount; ++i) {
3357         pret = PrlVmCfg_GetNetAdapter(sdkdom, i, &adapter);
3358         prlsdkCheckRetGoto(pret, cleanup);
3359 
3360         pret = prlsdkGetStringParamBuf(PrlVmDevNet_GetMacAddress,
3361                                        adapter, adapterMac, sizeof(adapterMac));
3362         prlsdkCheckRetGoto(pret, cleanup);
3363 
3364         if (STREQ(adapterMac, expectedMac))
3365             return adapter;
3366 
3367         PrlHandle_Free(adapter);
3368         adapter = PRL_INVALID_HANDLE;
3369     }
3370 
3371     virReportError(VIR_ERR_INTERNAL_ERROR,
3372                    _("No net with mac '%s'"), virMacAddrFormat(mac, virMac));
3373 
3374  cleanup:
3375     PrlHandle_Free(adapter);
3376     return adapter;
3377 }
3378 
prlsdkConfigureDisk(struct _vzDriver * driver,PRL_HANDLE sdkdom,virDomainDiskDef * disk,bool create)3379 static int prlsdkConfigureDisk(struct _vzDriver *driver,
3380                                PRL_HANDLE sdkdom,
3381                                virDomainDiskDef *disk,
3382                                bool create)
3383 {
3384     PRL_RESULT pret;
3385     PRL_HANDLE sdkdisk = PRL_INVALID_HANDLE;
3386     int ret = -1;
3387     PRL_VM_DEV_EMULATION_TYPE emutype;
3388     PRL_MASS_STORAGE_INTERFACE_TYPE sdkbus;
3389     int idx;
3390     virDomainDeviceDriveAddress *drive;
3391     PRL_DEVICE_TYPE devType;
3392     PRL_CLUSTERED_DEVICE_SUBTYPE scsiModel;
3393     const char *path = disk->src->path ? : "";
3394 
3395     if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
3396         devType = PDE_HARD_DISK;
3397     else
3398         devType = PDE_OPTICAL_DISK;
3399 
3400     if (create) {
3401         pret = PrlVmCfg_CreateVmDev(sdkdom, devType, &sdkdisk);
3402         prlsdkCheckRetGoto(pret, cleanup);
3403     } else {
3404         sdkdisk = prlsdkGetDisk(sdkdom, disk);
3405         if (sdkdisk == PRL_INVALID_HANDLE)
3406             return -1;
3407     }
3408 
3409     pret = PrlVmDev_SetEnabled(sdkdisk, 1);
3410     prlsdkCheckRetGoto(pret, cleanup);
3411 
3412     pret = PrlVmDev_SetConnected(sdkdisk, 1);
3413     prlsdkCheckRetGoto(pret, cleanup);
3414 
3415     if (disk->src->type == VIR_STORAGE_TYPE_FILE)
3416         emutype = PDT_USE_IMAGE_FILE;
3417     else
3418         emutype = PDT_USE_REAL_DEVICE;
3419 
3420     pret = PrlVmDev_SetEmulatedType(sdkdisk, emutype);
3421     prlsdkCheckRetGoto(pret, cleanup);
3422 
3423     pret = PrlVmDev_SetSysName(sdkdisk, path);
3424     prlsdkCheckRetGoto(pret, cleanup);
3425 
3426     pret = PrlVmDev_SetFriendlyName(sdkdisk, path);
3427     prlsdkCheckRetGoto(pret, cleanup);
3428 
3429     drive = &disk->info.addr.drive;
3430 
3431     switch (disk->bus) {
3432     case VIR_DOMAIN_DISK_BUS_IDE:
3433         sdkbus = PMS_IDE_DEVICE;
3434         idx = 2 * drive->bus + drive->unit;
3435         break;
3436     case VIR_DOMAIN_DISK_BUS_SCSI:
3437         sdkbus = PMS_SCSI_DEVICE;
3438         idx = drive->unit;
3439         break;
3440     case VIR_DOMAIN_DISK_BUS_SATA:
3441         sdkbus = PMS_SATA_DEVICE;
3442         idx = drive->unit;
3443         break;
3444     case VIR_DOMAIN_DISK_BUS_FDC:
3445     case VIR_DOMAIN_DISK_BUS_NONE:
3446     case VIR_DOMAIN_DISK_BUS_VIRTIO:
3447     case VIR_DOMAIN_DISK_BUS_XEN:
3448     case VIR_DOMAIN_DISK_BUS_USB:
3449     case VIR_DOMAIN_DISK_BUS_UML:
3450     case VIR_DOMAIN_DISK_BUS_SD:
3451     case VIR_DOMAIN_DISK_BUS_LAST:
3452     default:
3453         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3454                        _("Specified disk bus is not "
3455                          "supported by vz driver."));
3456         goto cleanup;
3457     }
3458 
3459     if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
3460         if (vzGetDefaultSCSIModel(driver, &scsiModel) < 0)
3461             goto cleanup;
3462         pret = PrlVmDev_SetSubType(sdkdisk, scsiModel);
3463         prlsdkCheckRetGoto(pret, cleanup);
3464     }
3465 
3466     pret = PrlVmDev_SetIfaceType(sdkdisk, sdkbus);
3467     prlsdkCheckRetGoto(pret, cleanup);
3468 
3469     pret = PrlVmDev_SetStackIndex(sdkdisk, idx);
3470     prlsdkCheckRetGoto(pret, cleanup);
3471 
3472     if (devType == PDE_HARD_DISK) {
3473         pret = PrlVmDevHd_SetSerialNumber(sdkdisk, disk->serial);
3474         prlsdkCheckRetGoto(pret, cleanup);
3475     }
3476 
3477     return 0;
3478  cleanup:
3479     PrlHandle_Free(sdkdisk);
3480     return ret;
3481 }
3482 
3483 static PRL_HANDLE
prlsdkGetDisk(PRL_HANDLE sdkdom,virDomainDiskDef * disk)3484 prlsdkGetDisk(PRL_HANDLE sdkdom, virDomainDiskDef *disk)
3485 {
3486     PRL_RESULT pret;
3487     PRL_UINT32 num;
3488     size_t i;
3489     PRL_HANDLE sdkdisk = PRL_INVALID_HANDLE;
3490     virDomainDiskBus bus;
3491     char *dst = NULL;
3492     PRL_DEVICE_TYPE devType;
3493 
3494     if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
3495         devType = PDE_HARD_DISK;
3496     else
3497         devType = PDE_OPTICAL_DISK;
3498 
3499     pret = PrlVmCfg_GetDevsCountByType(sdkdom, devType, &num);
3500     prlsdkCheckRetGoto(pret, error);
3501 
3502     for (i = 0; i < num; ++i) {
3503         pret = PrlVmCfg_GetDevByType(sdkdom, devType, i, &sdkdisk);
3504         prlsdkCheckRetGoto(pret, error);
3505 
3506         if (prlsdkGetDiskId(sdkdisk, &bus, &dst) < 0)
3507             goto error;
3508 
3509         if (disk->bus == bus && STREQ(disk->dst, dst)) {
3510             VIR_FREE(dst);
3511             return sdkdisk;
3512         }
3513 
3514         PrlHandle_Free(sdkdisk);
3515         sdkdisk = PRL_INVALID_HANDLE;
3516         VIR_FREE(dst);
3517     }
3518 
3519     virReportError(VIR_ERR_INTERNAL_ERROR,
3520                    _("No disk with bus '%s' and target '%s'"),
3521                    virDomainDiskBusTypeToString(disk->bus), disk->dst);
3522     return PRL_INVALID_HANDLE;
3523 
3524  error:
3525     VIR_FREE(dst);
3526     PrlHandle_Free(sdkdisk);
3527     return PRL_INVALID_HANDLE;
3528 }
3529 
3530 int
prlsdkAttachDevice(struct _vzDriver * driver,virDomainObj * dom,virDomainDeviceDef * dev)3531 prlsdkAttachDevice(struct _vzDriver *driver,
3532                    virDomainObj *dom,
3533                    virDomainDeviceDef *dev)
3534 {
3535     struct vzDomObj *privdom = dom->privateData;
3536     PRL_HANDLE job = PRL_INVALID_HANDLE;
3537 
3538     job = PrlVm_BeginEdit(privdom->sdkdom);
3539     if (PRL_FAILED(waitDomainJob(job, dom)))
3540         return -1;
3541 
3542     switch (dev->type) {
3543     case VIR_DOMAIN_DEVICE_DISK:
3544         if (prlsdkConfigureDisk(driver, privdom->sdkdom,
3545                                 dev->data.disk, true) < 0)
3546             return -1;
3547 
3548         break;
3549     case VIR_DOMAIN_DEVICE_NET:
3550         if (!IS_CT(dom->def)) {
3551             virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3552                            _("attaching network device to VM is unsupported"));
3553             return -1;
3554         }
3555 
3556         if (prlsdkConfigureNet(driver, dom, privdom->sdkdom, dev->data.net,
3557                                IS_CT(dom->def), true) < 0)
3558             return -1;
3559 
3560         break;
3561     case VIR_DOMAIN_DEVICE_GRAPHICS:
3562         if (dom->def->ngraphics > 0) {
3563             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3564                            _("domain already has VNC graphics"));
3565             return -1;
3566         }
3567 
3568         if (prlsdkApplyGraphicsParams(privdom->sdkdom, dev->data.graphics) < 0)
3569             return -1;
3570 
3571         break;
3572     default:
3573         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3574                        _("attaching device type '%s' is unsupported"),
3575                        virDomainDeviceTypeToString(dev->type));
3576         return -1;
3577     }
3578 
3579     job = PrlVm_CommitEx(privdom->sdkdom, PVCF_DETACH_HDD_BUNDLE);
3580     if (PRL_FAILED(waitDomainJob(job, dom)))
3581         return -1;
3582 
3583     return 0;
3584 }
3585 
3586 int
prlsdkDetachDevice(struct _vzDriver * driver G_GNUC_UNUSED,virDomainObj * dom,virDomainDeviceDef * dev)3587 prlsdkDetachDevice(struct _vzDriver *driver G_GNUC_UNUSED,
3588                    virDomainObj *dom,
3589                    virDomainDeviceDef *dev)
3590 {
3591     int ret = -1;
3592     struct vzDomObj *privdom = dom->privateData;
3593     PRL_HANDLE job = PRL_INVALID_HANDLE;
3594     PRL_HANDLE sdkdev = PRL_INVALID_HANDLE;
3595     PRL_RESULT pret;
3596 
3597     job = PrlVm_BeginEdit(privdom->sdkdom);
3598     if (PRL_FAILED(waitDomainJob(job, dom)))
3599         goto cleanup;
3600 
3601     switch (dev->type) {
3602     case VIR_DOMAIN_DEVICE_DISK:
3603         sdkdev = prlsdkGetDisk(privdom->sdkdom, dev->data.disk);
3604         if (sdkdev == PRL_INVALID_HANDLE)
3605             goto cleanup;
3606 
3607         pret = PrlVmDev_Remove(sdkdev);
3608         prlsdkCheckRetGoto(pret, cleanup);
3609 
3610         break;
3611     case VIR_DOMAIN_DEVICE_NET:
3612         if (!IS_CT(dom->def)) {
3613             virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3614                            _("detaching network device from VM is unsupported"));
3615             goto cleanup;
3616         }
3617 
3618         sdkdev = prlsdkFindNetByMAC(privdom->sdkdom, &dev->data.net->mac);
3619         if (sdkdev == PRL_INVALID_HANDLE)
3620             goto cleanup;
3621 
3622         pret = PrlVmDev_Remove(sdkdev);
3623         prlsdkCheckRetGoto(pret, cleanup);
3624 
3625         break;
3626     case VIR_DOMAIN_DEVICE_GRAPHICS:
3627         if (dom->def->ngraphics < 1) {
3628             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3629                            _("cannot find VNC graphics device"));
3630             goto cleanup;
3631         }
3632 
3633         if (prlsdkApplyGraphicsParams(privdom->sdkdom, NULL) < 0)
3634             goto cleanup;
3635 
3636         break;
3637     default:
3638         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3639                        _("detaching device type '%s' is unsupported"),
3640                        virDomainDeviceTypeToString(dev->type));
3641         goto cleanup;
3642     }
3643 
3644     job = PrlVm_CommitEx(privdom->sdkdom, PVCF_DETACH_HDD_BUNDLE);
3645     if (PRL_FAILED(waitDomainJob(job, dom)))
3646         goto cleanup;
3647 
3648     ret = 0;
3649 
3650  cleanup:
3651 
3652     PrlHandle_Free(sdkdev);
3653     return ret;
3654 }
3655 
3656 int
prlsdkUpdateDevice(struct _vzDriver * driver,virDomainObj * dom,virDomainDeviceDef * dev)3657 prlsdkUpdateDevice(struct _vzDriver *driver,
3658                    virDomainObj *dom,
3659                    virDomainDeviceDef *dev)
3660 {
3661     struct vzDomObj *privdom = dom->privateData;
3662     PRL_HANDLE job = PRL_INVALID_HANDLE;
3663 
3664     job = PrlVm_BeginEdit(privdom->sdkdom);
3665     if (PRL_FAILED(waitDomainJob(job, dom)))
3666         return -1;
3667 
3668     switch (dev->type) {
3669     case VIR_DOMAIN_DEVICE_DISK:
3670         if (prlsdkConfigureDisk(driver, privdom->sdkdom, dev->data.disk,
3671                                 false) < 0)
3672             return -1;
3673 
3674         break;
3675     case VIR_DOMAIN_DEVICE_NET:
3676         if (prlsdkConfigureNet(driver, dom, privdom->sdkdom, dev->data.net,
3677                                IS_CT(dom->def), false) < 0)
3678             return -1;
3679 
3680         break;
3681     case VIR_DOMAIN_DEVICE_GRAPHICS:
3682         if (dom->def->ngraphics < 1) {
3683             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3684                            _("cannot find VNC graphics device"));
3685             return -1;
3686         }
3687 
3688         if (prlsdkApplyGraphicsParams(privdom->sdkdom, dev->data.graphics) < 0)
3689             return -1;
3690 
3691         break;
3692     default:
3693         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3694                        _("updating device type '%s' is unsupported"),
3695                        virDomainDeviceTypeToString(dev->type));
3696         return -1;
3697     }
3698 
3699     job = PrlVm_CommitEx(privdom->sdkdom, PVCF_DETACH_HDD_BUNDLE);
3700     if (PRL_FAILED(waitDomainJob(job, dom)))
3701         return -1;
3702 
3703     return 0;
3704 }
3705 
3706 static int
prlsdkAddFS(PRL_HANDLE sdkdom,virDomainFSDef * fs)3707 prlsdkAddFS(PRL_HANDLE sdkdom, virDomainFSDef *fs)
3708 {
3709     PRL_RESULT pret;
3710     PRL_HANDLE sdkdisk = PRL_INVALID_HANDLE;
3711     int ret = -1;
3712     char *storage = NULL;
3713 
3714     if (fs->type == VIR_DOMAIN_FS_TYPE_TEMPLATE)
3715         return 0;
3716 
3717     if (prlsdkCheckFSUnsupportedParams(fs) < 0)
3718         return -1;
3719 
3720     pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_HARD_DISK, &sdkdisk);
3721     prlsdkCheckRetGoto(pret, cleanup);
3722 
3723     if (fs->type == VIR_DOMAIN_FS_TYPE_VOLUME) {
3724         storage = g_strdup_printf("libvirt://localhost/%s/%s",
3725                                   fs->src->srcpool->pool, fs->src->srcpool->volume);
3726         pret = PrlVmDevHd_SetStorageURL(sdkdisk, storage);
3727         prlsdkCheckRetGoto(pret, cleanup);
3728     }
3729 
3730     pret = PrlVmDev_SetEnabled(sdkdisk, 1);
3731     prlsdkCheckRetGoto(pret, cleanup);
3732 
3733     pret = PrlVmDev_SetConnected(sdkdisk, 1);
3734     prlsdkCheckRetGoto(pret, cleanup);
3735 
3736     pret = PrlVmDev_SetEmulatedType(sdkdisk, PDT_USE_IMAGE_FILE);
3737     prlsdkCheckRetGoto(pret, cleanup);
3738 
3739     pret = PrlVmDev_SetSysName(sdkdisk, fs->src->path);
3740     prlsdkCheckRetGoto(pret, cleanup);
3741 
3742     pret = PrlVmDev_SetImagePath(sdkdisk, fs->src->path);
3743     prlsdkCheckRetGoto(pret, cleanup);
3744 
3745     pret = PrlVmDev_SetFriendlyName(sdkdisk, fs->src->path);
3746     prlsdkCheckRetGoto(pret, cleanup);
3747 
3748     pret = PrlVmDevHd_SetMountPoint(sdkdisk, fs->dst);
3749     prlsdkCheckRetGoto(pret, cleanup);
3750 
3751     ret = 0;
3752 
3753  cleanup:
3754     VIR_FREE(storage);
3755     PrlHandle_Free(sdkdisk);
3756     return ret;
3757 }
3758 
3759 static int
prlsdkSetBootOrderCt(PRL_HANDLE sdkdom,virDomainDef * def)3760 prlsdkSetBootOrderCt(PRL_HANDLE sdkdom, virDomainDef *def)
3761 {
3762     size_t i;
3763     PRL_HANDLE hdd = PRL_INVALID_HANDLE;
3764     PRL_RESULT pret;
3765     bool rootfs = false;
3766     int ret = -1;
3767 
3768     for (i = 0; i < def->nfss; i++) {
3769 
3770         pret = prlsdkAddDeviceToBootList(sdkdom, i, PDE_HARD_DISK, i + 1);
3771         prlsdkCheckRetExit(pret, -1);
3772 
3773         if (STREQ(def->fss[i]->dst, "/"))
3774             rootfs = true;
3775     }
3776 
3777     if (!rootfs) {
3778         /* if we have root mounted we don't need to explicitly set boot order */
3779         pret = PrlVmCfg_GetHardDisk(sdkdom, def->nfss, &hdd);
3780         prlsdkCheckRetExit(pret, -1);
3781 
3782         PrlVmDevHd_SetMountPoint(hdd, "/");
3783         prlsdkCheckRetGoto(pret, cleanup);
3784     }
3785 
3786     ret = 0;
3787 
3788  cleanup:
3789     PrlHandle_Free(hdd);
3790     return ret;
3791 }
3792 
3793 static int
prlsdkSetBootOrderVm(PRL_HANDLE sdkdom,virDomainDef * def)3794 prlsdkSetBootOrderVm(PRL_HANDLE sdkdom, virDomainDef *def)
3795 {
3796     size_t i;
3797     int idx[VIR_DOMAIN_BOOT_LAST] = { 0 };
3798     int bootIndex = 0;
3799     PRL_RESULT pret;
3800     PRL_UINT32 num;
3801     int sdkType;
3802     virDomainBootOrder virType;
3803 
3804     for (i = 0; i < def->os.nBootDevs; ++i) {
3805         virType = def->os.bootDevs[i];
3806 
3807         switch ((int)virType) {
3808         case VIR_DOMAIN_BOOT_CDROM:
3809             sdkType = PDE_OPTICAL_DISK;
3810             break;
3811         case VIR_DOMAIN_BOOT_DISK:
3812             sdkType = PDE_HARD_DISK;
3813             break;
3814         case VIR_DOMAIN_BOOT_NET:
3815             sdkType = PDE_GENERIC_NETWORK_ADAPTER;
3816             break;
3817         default:
3818             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3819                            _("Unsupported boot device type: '%s'"),
3820                            virDomainBootTypeToString(virType));
3821             return -1;
3822         }
3823 
3824         pret = PrlVmCfg_GetDevsCountByType(sdkdom, sdkType, &num);
3825         prlsdkCheckRetExit(pret, -1);
3826 
3827         pret = prlsdkAddDeviceToBootList(sdkdom, idx[virType]++, sdkType, bootIndex++);
3828         prlsdkCheckRetExit(pret, -1);
3829     }
3830 
3831     return 0;
3832 }
3833 
3834 int
prlsdkDomainSetUserPassword(virDomainObj * dom,const char * user,const char * password)3835 prlsdkDomainSetUserPassword(virDomainObj *dom,
3836                             const char *user,
3837                             const char *password)
3838 {
3839     struct vzDomObj *privdom = dom->privateData;
3840     PRL_HANDLE job = PRL_INVALID_HANDLE;
3841 
3842     job = PrlVm_SetUserPasswd(privdom->sdkdom,
3843                               user,
3844                               password,
3845                               0);
3846 
3847     if (PRL_FAILED(waitDomainJob(job, dom)))
3848         return -1;
3849 
3850     return 0;
3851 }
3852 
3853 static int
prlsdkDoApplyConfig(struct _vzDriver * driver,virDomainObj * dom,PRL_HANDLE sdkdom,virDomainDef * def)3854 prlsdkDoApplyConfig(struct _vzDriver *driver,
3855                     virDomainObj *dom,
3856                     PRL_HANDLE sdkdom,
3857                     virDomainDef *def)
3858 {
3859     PRL_RESULT pret;
3860     size_t i;
3861     char uuidstr[VIR_UUID_STRING_BRACED_BUFLEN];
3862     char *mask = NULL;
3863 
3864     if (prlsdkCheckUnsupportedParams(sdkdom, def) < 0)
3865         return -1;
3866 
3867     if (def->description) {
3868         pret = PrlVmCfg_SetDescription(sdkdom, def->description);
3869         prlsdkCheckRetGoto(pret, error);
3870     }
3871 
3872     if (def->name) {
3873         pret = PrlVmCfg_SetName(sdkdom, def->name);
3874         prlsdkCheckRetGoto(pret, error);
3875     }
3876 
3877     if (def->uuid) {
3878         prlsdkUUIDFormat(def->uuid, uuidstr);
3879 
3880         pret = PrlVmCfg_SetUuid(sdkdom, uuidstr);
3881         prlsdkCheckRetGoto(pret, error);
3882     }
3883 
3884     pret = PrlVmCfg_SetRamSize(sdkdom, virDomainDefGetMemoryTotal(def) >> 10);
3885     prlsdkCheckRetGoto(pret, error);
3886 
3887     pret = PrlVmCfg_SetCpuCount(sdkdom, virDomainDefGetVcpus(def));
3888     prlsdkCheckRetGoto(pret, error);
3889 
3890     if (!(mask = virBitmapFormat(def->cpumask)))
3891         goto error;
3892 
3893     pret = PrlVmCfg_SetCpuMask(sdkdom, mask);
3894     prlsdkCheckRetGoto(pret, error);
3895     VIR_FREE(mask);
3896 
3897     switch ((int)def->os.arch) {
3898     case VIR_ARCH_X86_64:
3899         pret = PrlVmCfg_SetCpuMode(sdkdom, PCM_CPU_MODE_64);
3900         break;
3901     case VIR_ARCH_I686:
3902         pret = PrlVmCfg_SetCpuMode(sdkdom, PCM_CPU_MODE_32);
3903         break;
3904     default:
3905         virReportError(VIR_ERR_INTERNAL_ERROR,
3906                        _("Unknown CPU mode: %s"),
3907                        virArchToString(def->os.arch));
3908         goto error;
3909     }
3910     prlsdkCheckRetGoto(pret, error);
3911 
3912     if (prlsdkClearDevices(sdkdom) < 0)
3913         goto error;
3914 
3915     if (prlsdkRemoveBootDevices(sdkdom) < 0)
3916         goto error;
3917 
3918     for (i = 0; i < def->nnets; i++) {
3919         if (prlsdkConfigureNet(driver, dom, sdkdom, def->nets[i],
3920                                IS_CT(def), true) < 0)
3921             goto error;
3922     }
3923 
3924     if (def->ngraphics > 1) {
3925         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3926                        _("vz driver supports only VNC graphics"));
3927         goto error;
3928     }
3929 
3930     if (prlsdkApplyGraphicsParams(sdkdom,
3931                                   def->ngraphics == 1 ? def->graphics[0] : NULL) < 0)
3932         goto error;
3933 
3934     if (prlsdkApplyVideoParams(sdkdom, def) < 0)
3935         goto error;
3936 
3937     for (i = 0; i < def->nserials; i++) {
3938         if (prlsdkAddSerial(sdkdom, def->serials[i]) < 0)
3939             goto error;
3940     }
3941 
3942     /* It is important that we add filesystems first and then disks as we rely
3943      * on this information in prlsdkSetBootOrderCt */
3944     for (i = 0; i < def->nfss; i++) {
3945         if (prlsdkAddFS(sdkdom, def->fss[i]) < 0)
3946             goto error;
3947     }
3948 
3949     /* filesystems first, disks go after them as we rely on this order in
3950      * prlsdkSetBootOrderCt */
3951     for (i = 0; i < def->ndisks; i++) {
3952         if (prlsdkConfigureDisk(driver, sdkdom, def->disks[i],
3953                                 true) < 0)
3954             goto error;
3955     }
3956 
3957     if (IS_CT(def)) {
3958         if (prlsdkSetBootOrderCt(sdkdom, def) < 0)
3959             goto error;
3960     } else {
3961         if (prlsdkSetBootOrderVm(sdkdom, def) < 0)
3962             goto error;
3963     }
3964 
3965     return 0;
3966 
3967  error:
3968     VIR_FREE(mask);
3969 
3970     return -1;
3971 }
3972 
3973 int
prlsdkApplyConfig(struct _vzDriver * driver,virDomainObj * dom,virDomainDef * new)3974 prlsdkApplyConfig(struct _vzDriver *driver,
3975                   virDomainObj *dom,
3976                   virDomainDef *new)
3977 {
3978     struct vzDomObj *privdom = dom->privateData;
3979     PRL_HANDLE job = PRL_INVALID_HANDLE;
3980     int ret;
3981 
3982     job = PrlVm_BeginEdit(privdom->sdkdom);
3983     if (PRL_FAILED(waitDomainJob(job, dom)))
3984         return -1;
3985 
3986     ret = prlsdkDoApplyConfig(driver, dom, privdom->sdkdom, new);
3987 
3988     if (ret == 0) {
3989         job = PrlVm_CommitEx(privdom->sdkdom, PVCF_DETACH_HDD_BUNDLE);
3990         if (PRL_FAILED(waitDomainJob(job, dom)))
3991             ret = -1;
3992     }
3993 
3994     return ret;
3995 }
3996 
3997 int
prlsdkCreateVm(struct _vzDriver * driver,virDomainDef * def)3998 prlsdkCreateVm(struct _vzDriver *driver, virDomainDef *def)
3999 {
4000     PRL_HANDLE sdkdom = PRL_INVALID_HANDLE;
4001     PRL_HANDLE job = PRL_INVALID_HANDLE;
4002     PRL_HANDLE result = PRL_INVALID_HANDLE;
4003     PRL_HANDLE srvconf = PRL_INVALID_HANDLE;
4004     PRL_RESULT pret;
4005     int ret = -1;
4006 
4007     pret = PrlSrv_CreateVm(driver->server, &sdkdom);
4008     prlsdkCheckRetGoto(pret, cleanup);
4009 
4010     job = PrlSrv_GetSrvConfig(driver->server);
4011     if (PRL_FAILED(getJobResult(job, &result)))
4012         goto cleanup;
4013 
4014     pret = PrlResult_GetParamByIndex(result, 0, &srvconf);
4015     prlsdkCheckRetGoto(pret, cleanup);
4016 
4017     pret = PrlVmCfg_SetDefaultConfig(sdkdom, srvconf, PVS_GUEST_VER_LIN_REDHAT, 0);
4018     prlsdkCheckRetGoto(pret, cleanup);
4019 
4020     pret = PrlVmCfg_SetOfflineManagementEnabled(sdkdom, 0);
4021     prlsdkCheckRetGoto(pret, cleanup);
4022 
4023     if (prlsdkDoApplyConfig(driver, NULL, sdkdom, def) < 0)
4024         goto cleanup;
4025 
4026     job = PrlVm_Reg(sdkdom, "", 1);
4027     if (PRL_FAILED(waitJob(job)))
4028         goto cleanup;
4029 
4030     ret = 0;
4031 
4032  cleanup:
4033     PrlHandle_Free(sdkdom);
4034     PrlHandle_Free(srvconf);
4035     PrlHandle_Free(result);
4036 
4037     return ret;
4038 }
4039 
4040 static int
virStorageTranslatePoolLocal(virConnectPtr conn,virStorageSource * src)4041 virStorageTranslatePoolLocal(virConnectPtr conn, virStorageSource *src)
4042 {
4043     virStoragePoolPtr pool = NULL;
4044     virStorageVolPtr vol = NULL;
4045     virStorageVolInfo info;
4046     int ret = -1;
4047 
4048     if (!(pool = virStoragePoolLookupByName(conn, src->srcpool->pool)))
4049         return -1;
4050     if (virStoragePoolIsActive(pool) != 1) {
4051         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4052                        _("storage pool '%s' containing volume '%s' "
4053                          "is not active"), src->srcpool->pool,
4054                        src->srcpool->volume);
4055         goto cleanup;
4056     }
4057 
4058     if (!(vol = virStorageVolLookupByName(pool, src->srcpool->volume)))
4059         goto cleanup;
4060 
4061     if (virStorageVolGetInfo(vol, &info) < 0)
4062         goto cleanup;
4063 
4064     if (info.type != VIR_STORAGE_VOL_PLOOP) {
4065         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4066                        _("Unsupported volume format '%s'"),
4067                        virStorageVolTypeToString(info.type));
4068         goto cleanup;
4069     }
4070 
4071     if (!(src->path = virStorageVolGetPath(vol)))
4072         goto cleanup;
4073 
4074     ret = 0;
4075 
4076  cleanup:
4077     virObjectUnref(pool);
4078     virObjectUnref(vol);
4079     return ret;
4080 }
4081 
4082 
4083 int
prlsdkCreateCt(virConnectPtr conn,virDomainDef * def)4084 prlsdkCreateCt(virConnectPtr conn, virDomainDef *def)
4085 {
4086     PRL_HANDLE sdkdom = PRL_INVALID_HANDLE;
4087     PRL_GET_VM_CONFIG_PARAM_DATA confParam;
4088     PRL_HANDLE job = PRL_INVALID_HANDLE;
4089     PRL_HANDLE result = PRL_INVALID_HANDLE;
4090     PRL_RESULT pret;
4091     PRL_UINT32 flags;
4092     struct _vzConn *privconn = conn->privateData;
4093     struct _vzDriver *driver = privconn->driver;
4094     int ret = -1;
4095     int useTemplate = 0;
4096     size_t i;
4097 
4098     for (i = 0; i < def->nfss; i++) {
4099         if (useTemplate) {
4100             virReportError(VIR_ERR_INVALID_ARG, "%s",
4101                            _("Unsupported configuration"));
4102             return -1;
4103         }
4104         if (def->fss[i]->type == VIR_DOMAIN_FS_TYPE_TEMPLATE)
4105             useTemplate = 1;
4106         if (def->fss[i]->type == VIR_DOMAIN_FS_TYPE_VOLUME) {
4107             if (virStorageTranslatePoolLocal(conn, def->fss[i]->src) < 0)
4108                 goto cleanup;
4109         }
4110 
4111     }
4112 
4113     if (useTemplate && def->nfss > 1) {
4114         virReportError(VIR_ERR_INVALID_ARG, "%s",
4115                        _("Unsupported configuration"));
4116         return -1;
4117     }
4118 
4119     confParam.nVmType = PVT_CT;
4120     confParam.sConfigSample = "vswap.1024MB";
4121     confParam.nOsVersion = 0;
4122 
4123     job = PrlSrv_GetDefaultVmConfig(driver->server, &confParam, 0);
4124     if (PRL_FAILED(getJobResult(job, &result)))
4125         goto cleanup;
4126 
4127     pret = PrlResult_GetParamByIndex(result, 0, &sdkdom);
4128     prlsdkCheckRetGoto(pret, cleanup);
4129 
4130     if (useTemplate) {
4131         pret = PrlVmCfg_SetOsTemplate(sdkdom, def->fss[0]->src->path);
4132         prlsdkCheckRetGoto(pret, cleanup);
4133 
4134     }
4135 
4136     if (prlsdkDoApplyConfig(driver, NULL, sdkdom, def) < 0)
4137         goto cleanup;
4138 
4139     flags = PACF_NON_INTERACTIVE_MODE;
4140     if (!useTemplate)
4141         flags |= PRNVM_PRESERVE_DISK;
4142     job = PrlVm_RegEx(sdkdom, "", flags);
4143     if (PRL_FAILED(waitJob(job)))
4144         goto cleanup;
4145 
4146     ret = 0;
4147 
4148  cleanup:
4149     PrlHandle_Free(sdkdom);
4150     PrlHandle_Free(result);
4151     return ret;
4152 }
4153 
4154 /**
4155  * prlsdkDetachDomainHardDisks:
4156  *
4157  * @sdkdom: domain handle
4158  *
4159  * Returns 0 if hard disks were successfully detached or not detected.
4160  */
4161 static int
prlsdkDetachDomainHardDisks(virDomainObj * dom)4162 prlsdkDetachDomainHardDisks(virDomainObj *dom)
4163 {
4164     int ret = -1;
4165     PRL_RESULT pret;
4166     PRL_UINT32 hddCount;
4167     PRL_UINT32 i;
4168     PRL_HANDLE job;
4169     PRL_HANDLE sdkdisk = PRL_INVALID_HANDLE;
4170     struct vzDomObj *pdom = dom->privateData;
4171     PRL_HANDLE sdkdom = pdom->sdkdom;
4172 
4173     job = PrlVm_BeginEdit(sdkdom);
4174     if (PRL_FAILED(waitDomainJob(job, dom)))
4175         goto cleanup;
4176 
4177     pret = PrlVmCfg_GetHardDisksCount(sdkdom, &hddCount);
4178     prlsdkCheckRetGoto(pret, cleanup);
4179 
4180     for (i = 0; i < hddCount; ++i) {
4181         pret = PrlVmCfg_GetHardDisk(sdkdom, 0, &sdkdisk);
4182         prlsdkCheckRetGoto(pret, cleanup);
4183 
4184         pret = PrlVmDev_Remove(sdkdisk);
4185         prlsdkCheckRetGoto(pret, cleanup);
4186 
4187         PrlHandle_Free(sdkdisk);
4188         sdkdisk = PRL_INVALID_HANDLE;
4189     }
4190 
4191     job = PrlVm_CommitEx(sdkdom, PVCF_DETACH_HDD_BUNDLE);
4192     if (PRL_FAILED(waitDomainJob(job, dom)))
4193         goto cleanup;
4194 
4195     ret = 0;
4196 
4197  cleanup:
4198     PrlHandle_Free(sdkdisk);
4199     return ret;
4200 }
4201 
4202 int
prlsdkUnregisterDomain(struct _vzDriver * driver,virDomainObj * dom,unsigned int flags)4203 prlsdkUnregisterDomain(struct _vzDriver *driver, virDomainObj *dom, unsigned int flags)
4204 {
4205     struct vzDomObj *privdom = dom->privateData;
4206     PRL_HANDLE job;
4207     virDomainSnapshotObjList *snapshots = NULL;
4208     VIRTUAL_MACHINE_STATE domainState;
4209     int ret = -1;
4210     int num;
4211 
4212     if (prlsdkGetDomainState(dom, privdom->sdkdom, &domainState) < 0)
4213         return -1;
4214 
4215     if (VMS_SUSPENDED == domainState &&
4216         !(flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE)) {
4217 
4218         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
4219                        _("Refusing to undefine while domain managed "
4220                          "save image exists"));
4221         return -1;
4222     }
4223 
4224     if (!(snapshots = prlsdkLoadSnapshots(dom)))
4225         return -1;
4226 
4227     if ((num = virDomainSnapshotObjListNum(snapshots, NULL, 0)) < 0)
4228         goto cleanup;
4229 
4230     if (num > 0 && !(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
4231             virReportError(VIR_ERR_OPERATION_INVALID, "%s",
4232                            _("Refusing to undefine while snapshots exist"));
4233         goto cleanup;
4234     }
4235 
4236     if (prlsdkDetachDomainHardDisks(dom))
4237         goto cleanup;
4238 
4239     job = PrlVm_Delete(privdom->sdkdom, PRL_INVALID_HANDLE);
4240     if (PRL_FAILED(waitDomainJob(job, dom)))
4241         goto cleanup;
4242 
4243     prlsdkSendEvent(driver, dom, VIR_DOMAIN_EVENT_UNDEFINED,
4244                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
4245 
4246     virDomainObjListRemove(driver->domains, dom);
4247 
4248     ret = 0;
4249  cleanup:
4250 
4251     virDomainSnapshotObjListFree(snapshots);
4252     return ret;
4253 }
4254 
4255 int
prlsdkDomainManagedSaveRemove(virDomainObj * dom)4256 prlsdkDomainManagedSaveRemove(virDomainObj *dom)
4257 {
4258     struct vzDomObj *privdom = dom->privateData;
4259     PRL_HANDLE job;
4260 
4261     job = PrlVm_DropSuspendedState(privdom->sdkdom);
4262     if (PRL_FAILED(waitDomainJob(job, dom)))
4263         return -1;
4264 
4265     return 0;
4266 }
4267 
4268 static int
prlsdkExtractStatsParam(PRL_HANDLE sdkstats,const char * name,long long * val)4269 prlsdkExtractStatsParam(PRL_HANDLE sdkstats, const char *name, long long *val)
4270 {
4271     PRL_HANDLE param = PRL_INVALID_HANDLE;
4272     PRL_RESULT pret;
4273     PRL_INT64 pval = 0;
4274     int ret = -1;
4275 
4276     pret = PrlEvent_GetParamByName(sdkstats, name, &param);
4277     if (pret == PRL_ERR_NO_DATA) {
4278         *val = -1;
4279         ret = 0;
4280         goto cleanup;
4281     } else if (PRL_FAILED(pret)) {
4282         logPrlError(pret);
4283         goto cleanup;
4284     }
4285     pret = PrlEvtPrm_ToInt64(param, &pval);
4286     prlsdkCheckRetGoto(pret, cleanup);
4287 
4288     *val = pval;
4289     ret = 0;
4290 
4291  cleanup:
4292     PrlHandle_Free(param);
4293     return ret;
4294 }
4295 
4296 #define PARALLELS_STATISTICS_TIMEOUT (60 * 1000)
4297 
4298 int
prlsdkGetBlockStats(PRL_HANDLE sdkstats,virDomainDiskDef * disk,virDomainBlockStatsPtr stats,bool isCt)4299 prlsdkGetBlockStats(PRL_HANDLE sdkstats,
4300                     virDomainDiskDef *disk,
4301                     virDomainBlockStatsPtr stats,
4302                     bool isCt)
4303 {
4304     virDomainDeviceDriveAddress *address;
4305     int idx;
4306     const char *prefix;
4307     int ret = -1;
4308     char *name = NULL;
4309 
4310     address = &disk->info.addr.drive;
4311 
4312     if (isCt) {
4313         prefix = "hdd";
4314         idx = address->unit;
4315     } else {
4316         switch (disk->bus) {
4317         case VIR_DOMAIN_DISK_BUS_IDE:
4318             prefix = "ide";
4319             idx = address->bus * 2 + address->unit;
4320             break;
4321         case VIR_DOMAIN_DISK_BUS_SATA:
4322             prefix = "sata";
4323             idx = address->unit;
4324             break;
4325         case VIR_DOMAIN_DISK_BUS_SCSI:
4326             prefix = "scsi";
4327             idx = address->unit;
4328             break;
4329         case VIR_DOMAIN_DISK_BUS_FDC:
4330         case VIR_DOMAIN_DISK_BUS_NONE:
4331         case VIR_DOMAIN_DISK_BUS_VIRTIO:
4332         case VIR_DOMAIN_DISK_BUS_XEN:
4333         case VIR_DOMAIN_DISK_BUS_USB:
4334         case VIR_DOMAIN_DISK_BUS_UML:
4335         case VIR_DOMAIN_DISK_BUS_SD:
4336         case VIR_DOMAIN_DISK_BUS_LAST:
4337         default:
4338             virReportError(VIR_ERR_INTERNAL_ERROR,
4339                            _("Unknown disk bus: %X"), disk->bus);
4340             goto cleanup;
4341         }
4342     }
4343 
4344 
4345 #define PRLSDK_GET_STAT_PARAM(VAL, TYPE, NAME) \
4346     name = g_strdup_printf("devices.%s%d.%s", prefix, idx, NAME); \
4347     if (prlsdkExtractStatsParam(sdkstats, name, &stats->VAL) < 0) \
4348         goto cleanup; \
4349     VIR_FREE(name);
4350 
4351     PARALLELS_BLOCK_STATS_FOREACH(PRLSDK_GET_STAT_PARAM)
4352 
4353 #undef PRLSDK_GET_STAT_PARAM
4354 
4355     ret = 0;
4356 
4357  cleanup:
4358 
4359     VIR_FREE(name);
4360     return ret;
4361 }
4362 
4363 
4364 static PRL_HANDLE
prlsdkFindNetByPath(PRL_HANDLE sdkdom,const char * path)4365 prlsdkFindNetByPath(PRL_HANDLE sdkdom, const char *path)
4366 {
4367     PRL_UINT32 count = 0;
4368     PRL_RESULT pret;
4369     size_t i;
4370     char *name = NULL;
4371     PRL_HANDLE net = PRL_INVALID_HANDLE;
4372 
4373     pret = PrlVmCfg_GetNetAdaptersCount(sdkdom, &count);
4374     prlsdkCheckRetGoto(pret, error);
4375 
4376     for (i = 0; i < count; ++i) {
4377         pret = PrlVmCfg_GetNetAdapter(sdkdom, i, &net);
4378         prlsdkCheckRetGoto(pret, error);
4379 
4380         if (!(name = prlsdkGetStringParamVar(PrlVmDevNet_GetHostInterfaceName,
4381                                              net)))
4382             goto error;
4383 
4384         if (STREQ(name, path))
4385             break;
4386 
4387         VIR_FREE(name);
4388         PrlHandle_Free(net);
4389         net = PRL_INVALID_HANDLE;
4390     }
4391 
4392     if (net == PRL_INVALID_HANDLE)
4393         virReportError(VIR_ERR_INVALID_ARG,
4394                        _("invalid path, '%s' is not a known interface"), path);
4395     return net;
4396 
4397  error:
4398     VIR_FREE(name);
4399     PrlHandle_Free(net);
4400     return PRL_INVALID_HANDLE;
4401 }
4402 
4403 int
prlsdkGetNetStats(PRL_HANDLE sdkstats,PRL_HANDLE sdkdom,const char * device,virDomainInterfaceStatsPtr stats)4404 prlsdkGetNetStats(PRL_HANDLE sdkstats, PRL_HANDLE sdkdom, const char *device,
4405                   virDomainInterfaceStatsPtr stats)
4406 {
4407     int ret = -1;
4408     PRL_UINT32 net_index = -1;
4409     char *name = NULL;
4410     PRL_RESULT pret;
4411     PRL_HANDLE net = PRL_INVALID_HANDLE;
4412     virMacAddr mac;
4413 
4414     if (virMacAddrParse(device, &mac) == 0)
4415         net = prlsdkFindNetByMAC(sdkdom, &mac);
4416     else
4417         net = prlsdkFindNetByPath(sdkdom, device);
4418 
4419     if (net == PRL_INVALID_HANDLE)
4420        goto cleanup;
4421 
4422     pret = PrlVmDev_GetIndex(net, &net_index);
4423     prlsdkCheckRetGoto(pret, cleanup);
4424 
4425 #define PRLSDK_GET_NET_COUNTER(VAL, NAME) \
4426     name = g_strdup_printf("net.nic%u.%s", net_index, NAME); \
4427     if (prlsdkExtractStatsParam(sdkstats, name, &stats->VAL) < 0) \
4428         goto cleanup; \
4429     VIR_FREE(name);
4430 
4431     PRLSDK_GET_NET_COUNTER(rx_bytes, "bytes_in")
4432     PRLSDK_GET_NET_COUNTER(rx_packets, "pkts_in")
4433     PRLSDK_GET_NET_COUNTER(tx_bytes, "bytes_out")
4434     PRLSDK_GET_NET_COUNTER(tx_packets, "pkts_out")
4435     stats->rx_errs = -1;
4436     stats->rx_drop = -1;
4437     stats->tx_errs = -1;
4438     stats->tx_drop = -1;
4439 
4440 #undef PRLSDK_GET_NET_COUNTER
4441     ret = 0;
4442 
4443  cleanup:
4444     VIR_FREE(name);
4445     PrlHandle_Free(net);
4446 
4447     return ret;
4448 }
4449 
4450 int
prlsdkGetVcpuStats(PRL_HANDLE sdkstats,int idx,unsigned long long * vtime)4451 prlsdkGetVcpuStats(PRL_HANDLE sdkstats, int idx, unsigned long long *vtime)
4452 {
4453     char *name = NULL;
4454     long long ptime = 0;
4455     int ret = -1;
4456 
4457     name = g_strdup_printf("guest.vcpu%u.time", (unsigned int)idx);
4458     if (prlsdkExtractStatsParam(sdkstats, name, &ptime) < 0)
4459         goto cleanup;
4460     *vtime = ptime == -1 ? 0 : ptime;
4461     ret = 0;
4462 
4463  cleanup:
4464     VIR_FREE(name);
4465     return ret;
4466 }
4467 
4468 int
prlsdkGetMemoryStats(PRL_HANDLE sdkstats,virDomainMemoryStatPtr stats,unsigned int nr_stats)4469 prlsdkGetMemoryStats(PRL_HANDLE sdkstats,
4470                      virDomainMemoryStatPtr stats,
4471                      unsigned int nr_stats)
4472 {
4473     long long v = 0, t = 0, u = 0;
4474     size_t i = 0;
4475 
4476 #define PRLSDK_GET_COUNTER(NAME, VALUE) \
4477     if (prlsdkExtractStatsParam(sdkstats, NAME, &VALUE) < 0) \
4478         return -1; \
4479 
4480 #define PRLSDK_MEMORY_STAT_SET(TAG, VALUE) \
4481     if (i < nr_stats) { \
4482         stats[i].tag = (TAG); \
4483         stats[i].val = (VALUE); \
4484         i++; \
4485     }
4486 
4487     i = 0;
4488 
4489     // count to kb
4490     PRLSDK_GET_COUNTER("guest.ram.swap_in", v)
4491     if (v != -1)
4492         PRLSDK_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_SWAP_IN, v << 12)
4493 
4494     PRLSDK_GET_COUNTER("guest.ram.swap_out", v)
4495     if (v != -1)
4496         PRLSDK_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_SWAP_OUT, v << 12)
4497 
4498     PRLSDK_GET_COUNTER("guest.ram.minor_fault", v)
4499     if (v != -1)
4500         PRLSDK_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT, v)
4501 
4502     PRLSDK_GET_COUNTER("guest.ram.major_fault", v)
4503     if (v != -1)
4504         PRLSDK_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT, v)
4505 
4506     PRLSDK_GET_COUNTER("guest.ram.total", v)
4507     if (v != -1)
4508         PRLSDK_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_AVAILABLE, v << 10)
4509 
4510     PRLSDK_GET_COUNTER("guest.ram.balloon_actual", v)
4511     if (v != -1)
4512         PRLSDK_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON, v << 10)
4513 
4514     PRLSDK_GET_COUNTER("guest.ram.usage", u)
4515     PRLSDK_GET_COUNTER("guest.ram.total", t)
4516     if (u != -1 && t != -1)
4517         PRLSDK_MEMORY_STAT_SET(VIR_DOMAIN_MEMORY_STAT_UNUSED, (t - u) << 10)
4518 
4519 #undef PRLSDK_GET_COUNTER
4520 #undef PRLSDK_MEMORY_STAT_SET
4521 
4522     return i;
4523 }
4524 
4525 /* memsize is in MiB */
prlsdkSetMemsize(virDomainObj * dom,unsigned int memsize)4526 int prlsdkSetMemsize(virDomainObj *dom, unsigned int memsize)
4527 {
4528     struct vzDomObj *privdom = dom->privateData;
4529     PRL_HANDLE job;
4530     PRL_RESULT pret;
4531 
4532     job = PrlVm_BeginEdit(privdom->sdkdom);
4533     if (PRL_FAILED(waitDomainJob(job, dom)))
4534         return -1;
4535 
4536     pret = PrlVmCfg_SetRamSize(privdom->sdkdom, memsize);
4537     prlsdkCheckRetExit(pret, -1);
4538 
4539     job = PrlVm_CommitEx(privdom->sdkdom, 0);
4540     if (PRL_FAILED(waitDomainJob(job, dom)))
4541         return -1;
4542 
4543     return 0;
4544 }
4545 
4546 static long long
prlsdkParseDateTime(const char * str)4547 prlsdkParseDateTime(const char *str)
4548 {
4549     g_autoptr(GDateTime) then = NULL;
4550     g_autoptr(GTimeZone) tz = g_time_zone_new_utc();
4551     char *tmp;
4552     int year, mon, mday, hour, min, sec;
4553 
4554     /* Expect: YYYY-MM-DD HH:MM:SS (%d-%d-%dT%d:%d:%d)  eg 2010-11-28 14:29:01 */
4555     if (/* year */
4556         virStrToLong_i(str, &tmp, 10, &year) < 0 || *tmp != '-' ||
4557         /* month */
4558         virStrToLong_i(tmp+1, &tmp, 10, &mon) < 0 || *tmp != '-' ||
4559         /* day */
4560         virStrToLong_i(tmp+1, &tmp, 10, &mday) < 0 || *tmp != ' ' ||
4561         /* hour */
4562         virStrToLong_i(tmp+1, &tmp, 10, &hour) < 0 || *tmp != ':' ||
4563         /* minute */
4564         virStrToLong_i(tmp+1, &tmp, 10, &min) < 0 || *tmp != ':' ||
4565         /* second */
4566         virStrToLong_i(tmp+1, &tmp, 10, &sec) < 0 || *tmp != '\0') {
4567         virReportError(VIR_ERR_INTERNAL_ERROR,
4568                        _("unexpected DateTime format: '%s'"), str);
4569         return -1;
4570     }
4571 
4572     then = g_date_time_new(tz, year, mon, mday, hour, min, sec);
4573     return (long long)g_date_time_to_unix(then);
4574 }
4575 
4576 static virDomainSnapshotObjList *
prlsdkParseSnapshotTree(const char * treexml)4577 prlsdkParseSnapshotTree(const char *treexml)
4578 {
4579     virDomainSnapshotObjList *ret = NULL;
4580     g_autoptr(xmlDoc) xml = NULL;
4581     g_autoptr(xmlXPathContext) ctxt = NULL;
4582     xmlNodePtr root;
4583     xmlNodePtr *nodes = NULL;
4584     virDomainSnapshotDef *def = NULL;
4585     virDomainMomentObj *snapshot;
4586     virDomainSnapshotObjList *snapshots = NULL;
4587     char *xmlstr = NULL;
4588     int n;
4589     size_t i;
4590 
4591     if (!(snapshots = virDomainSnapshotObjListNew()))
4592         return NULL;
4593 
4594     if (*treexml == '\0')
4595         return snapshots;
4596 
4597     if (!(xml = virXMLParse(NULL, treexml, _("(snapshot_tree)"), NULL, false)))
4598         goto cleanup;
4599 
4600     root = xmlDocGetRootElement(xml);
4601     if (!virXMLNodeNameEqual(root, "ParallelsSavedStates")) {
4602         virReportError(VIR_ERR_INTERNAL_ERROR,
4603                        _("unexpected root element: '%s'"), root->name);
4604         goto cleanup;
4605     }
4606 
4607     if (!(ctxt = virXMLXPathContextNew(xml)))
4608         goto cleanup;
4609 
4610     ctxt->node = root;
4611 
4612     if ((n = virXPathNodeSet("//SavedStateItem", ctxt, &nodes)) < 0) {
4613         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4614                        _("cannot extract snapshot nodes"));
4615         goto cleanup;
4616     }
4617 
4618     for (i = 0; i < n; i++) {
4619         if (nodes[i]->parent == root)
4620             continue;
4621 
4622         def = g_new0(virDomainSnapshotDef, 1);
4623 
4624         ctxt->node = nodes[i];
4625 
4626         def->parent.name = virXPathString("string(./@guid)", ctxt);
4627         if (!def->parent.name) {
4628             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4629                            _("missing 'guid' attribute"));
4630             goto cleanup;
4631         }
4632 
4633         def->parent.parent_name = virXPathString("string(../@guid)", ctxt);
4634 
4635         xmlstr = virXPathString("string(./DateTime)", ctxt);
4636         if (!xmlstr) {
4637             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4638                            _("missing 'DateTime' element"));
4639             goto cleanup;
4640         }
4641         if ((def->parent.creationTime = prlsdkParseDateTime(xmlstr)) < 0)
4642             goto cleanup;
4643         VIR_FREE(xmlstr);
4644 
4645         def->parent.description = virXPathString("string(./Description)", ctxt);
4646 
4647         def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
4648         xmlstr = virXPathString("string(./@state)", ctxt);
4649         if (!xmlstr) {
4650             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4651                            _("missing 'state' attribute"));
4652             goto cleanup;
4653         } else if (STREQ(xmlstr, "poweron")) {
4654             def->state = VIR_DOMAIN_RUNNING;
4655             def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
4656         } else if (STREQ(xmlstr, "pause")) {
4657             def->state = VIR_DOMAIN_PAUSED;
4658             def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
4659         } else if (STREQ(xmlstr, "suspend")) {
4660             def->state = VIR_DOMAIN_SHUTOFF;
4661         } else if (STREQ(xmlstr, "poweroff")) {
4662             def->state = VIR_DOMAIN_SHUTOFF;
4663         } else {
4664             virReportError(VIR_ERR_INTERNAL_ERROR,
4665                            _("unexpected snapshot state: %s"), xmlstr);
4666         }
4667         VIR_FREE(xmlstr);
4668 
4669         if (!(snapshot = virDomainSnapshotAssignDef(snapshots, def)))
4670             goto cleanup;
4671         def = NULL;
4672 
4673         xmlstr = virXPathString("string(./@current)", ctxt);
4674         if (xmlstr && STREQ("yes", xmlstr)) {
4675             if (virDomainSnapshotGetCurrent(snapshots)) {
4676                 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4677                                _("too many current snapshots"));
4678                 VIR_FREE(xmlstr);
4679                 goto cleanup;
4680             }
4681             virDomainSnapshotSetCurrent(snapshots, snapshot);
4682         }
4683         VIR_FREE(xmlstr);
4684     }
4685 
4686     if (virDomainSnapshotUpdateRelations(snapshots) < 0) {
4687         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4688                        _("snapshots have inconsistent relations"));
4689         goto cleanup;
4690     }
4691 
4692     ret = g_steal_pointer(&snapshots);
4693 
4694  cleanup:
4695     virDomainSnapshotObjListFree(snapshots);
4696     VIR_FREE(nodes);
4697     VIR_FREE(xmlstr);
4698     VIR_FREE(def);
4699 
4700     return ret;
4701 }
4702 
4703 virDomainSnapshotObjList *
prlsdkLoadSnapshots(virDomainObj * dom)4704 prlsdkLoadSnapshots(virDomainObj *dom)
4705 {
4706     virDomainSnapshotObjList *ret = NULL;
4707     PRL_HANDLE job;
4708     PRL_HANDLE result = PRL_INVALID_HANDLE;
4709     struct vzDomObj *privdom = dom->privateData;
4710     char *treexml = NULL;
4711 
4712     job = PrlVm_GetSnapshotsTreeEx(privdom->sdkdom, PGST_WITHOUT_SCREENSHOTS);
4713     if (PRL_FAILED(getDomainJobResult(job, dom, &result)))
4714         goto cleanup;
4715 
4716     if (!(treexml = prlsdkGetStringParamVar(PrlResult_GetParamAsString, result)))
4717         goto cleanup;
4718 
4719     ret = prlsdkParseSnapshotTree(treexml);
4720  cleanup:
4721 
4722     PrlHandle_Free(result);
4723     VIR_FREE(treexml);
4724     return ret;
4725 }
4726 
prlsdkCreateSnapshot(virDomainObj * dom,const char * description)4727 int prlsdkCreateSnapshot(virDomainObj *dom, const char *description)
4728 {
4729     struct vzDomObj *privdom = dom->privateData;
4730     PRL_HANDLE job;
4731 
4732     job = PrlVm_CreateSnapshot(privdom->sdkdom, "",
4733                                description ? : "");
4734     if (PRL_FAILED(waitDomainJob(job, dom)))
4735         return -1;
4736 
4737     return 0;
4738 }
4739 
prlsdkDeleteSnapshot(virDomainObj * dom,const char * uuid,bool children)4740 int prlsdkDeleteSnapshot(virDomainObj *dom, const char *uuid, bool children)
4741 {
4742     struct vzDomObj *privdom = dom->privateData;
4743     PRL_HANDLE job;
4744 
4745     job = PrlVm_DeleteSnapshot(privdom->sdkdom, uuid, children);
4746     if (PRL_FAILED(waitDomainJob(job, dom)))
4747         return -1;
4748 
4749     return 0;
4750 }
4751 
prlsdkSwitchToSnapshot(virDomainObj * dom,const char * uuid,bool paused)4752 int prlsdkSwitchToSnapshot(virDomainObj *dom, const char *uuid, bool paused)
4753 {
4754     struct vzDomObj *privdom = dom->privateData;
4755     PRL_HANDLE job;
4756     PRL_UINT32 flags = 0;
4757 
4758     if (paused)
4759         flags |= PSSF_SKIP_RESUME;
4760 
4761     job = PrlVm_SwitchToSnapshotEx(privdom->sdkdom, uuid, flags);
4762     if (PRL_FAILED(waitDomainJob(job, dom)))
4763         return -1;
4764 
4765     return 0;
4766 }
4767 
4768 /* high security is default choice for 2 reasons:
4769  * 1. as this is the highest set security we can't get
4770  * reject from server with high security settings
4771  * 2. this is on par with security level of driver
4772  * connection to dispatcher
4773  */
4774 
4775 #define PRLSDK_MIGRATION_FLAGS (PSL_HIGH_SECURITY | PVMT_DONT_CREATE_DISK)
4776 
prlsdkMigrate(virDomainObj * dom,virURI * uri,const unsigned char * session_uuid,const char * dname,unsigned int flags)4777 int prlsdkMigrate(virDomainObj *dom, virURI *uri,
4778                   const unsigned char *session_uuid,
4779                   const char *dname,
4780                   unsigned int flags)
4781 {
4782     struct vzDomObj *privdom = dom->privateData;
4783     PRL_HANDLE job = PRL_INVALID_HANDLE;
4784     char uuidstr[VIR_UUID_STRING_BRACED_BUFLEN];
4785     PRL_UINT32 vzflags = PRLSDK_MIGRATION_FLAGS;
4786 
4787     if (flags & VIR_MIGRATE_PAUSED)
4788         vzflags |= PVMT_DONT_RESUME_VM;
4789 
4790     prlsdkUUIDFormat(session_uuid, uuidstr);
4791     job = PrlVm_MigrateWithRenameEx(privdom->sdkdom, uri->server,
4792                                     uri->port, uuidstr,
4793                                     dname == NULL ? "" : dname,
4794                                     "",
4795                                     vzflags,
4796                                     0,
4797                                     PRL_TRUE
4798                                     );
4799 
4800     if (PRL_FAILED(waitDomainJob(job, dom)))
4801         return -1;
4802 
4803     return 0;
4804 }
4805 
prlsdkSetCpuCount(virDomainObj * dom,unsigned int count)4806 int prlsdkSetCpuCount(virDomainObj *dom, unsigned int count)
4807 {
4808     struct vzDomObj *privdom = dom->privateData;
4809     PRL_HANDLE job;
4810     PRL_RESULT pret;
4811 
4812     job = PrlVm_BeginEdit(privdom->sdkdom);
4813     if (PRL_FAILED(waitDomainJob(job, dom)))
4814         return -1;
4815 
4816     pret = PrlVmCfg_SetCpuCount(privdom->sdkdom, count);
4817     prlsdkCheckRetExit(pret, -1);
4818 
4819     job = PrlVm_CommitEx(privdom->sdkdom, 0);
4820     if (PRL_FAILED(waitDomainJob(job, dom)))
4821         return -1;
4822 
4823     return 0;
4824 }
4825 
prlsdkResizeImage(virDomainObj * dom,virDomainDiskDef * disk,unsigned long long newsize)4826 int prlsdkResizeImage(virDomainObj *dom, virDomainDiskDef *disk,
4827                       unsigned long long newsize)
4828 {
4829     int ret = -1;
4830     PRL_RESULT pret;
4831     struct vzDomObj *privdom = dom->privateData;
4832     PRL_UINT32 emulatedType;
4833     PRL_HANDLE job = PRL_INVALID_HANDLE;
4834     PRL_HANDLE prldisk = PRL_INVALID_HANDLE;
4835 
4836     prldisk = prlsdkGetDisk(privdom->sdkdom, disk);
4837     if (prldisk == PRL_INVALID_HANDLE)
4838         goto cleanup;
4839 
4840     pret = PrlVmDev_GetEmulatedType(prldisk, &emulatedType);
4841     prlsdkCheckRetGoto(pret, cleanup);
4842 
4843     if (emulatedType != PDT_USE_IMAGE_FILE &&
4844         emulatedType != PDT_USE_FILE_SYSTEM) {
4845         virReportError(VIR_ERR_INVALID_ARG, "%s",
4846                        _("Only disk image supported for resize"));
4847         goto cleanup;
4848     }
4849 
4850     job = PrlVmDev_ResizeImage(prldisk, newsize,
4851                                PRIF_RESIZE_LAST_PARTITION);
4852     if (PRL_FAILED(waitDomainJob(job, dom)))
4853         goto cleanup;
4854 
4855     ret = 0;
4856 
4857  cleanup:
4858 
4859     PrlHandle_Free(prldisk);
4860     return ret;
4861 }
4862