return ret;
}
+static int
+bhyveDomainShutdown(virDomainPtr dom)
+{
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ if (!(vm = bhyveDomObjFromDomain(dom)))
+ goto cleanup;
+
+ if (virDomainShutdownEnsureACL(dom->conn, vm->def) < 0)
+ goto cleanup;
+
+ if (!virDomainObjIsActive(vm)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("Domain is not running"));
+ goto cleanup;
+ }
+
+ ret = virBhyveProcessShutdown(vm);
+
+ cleanup:
+ if (vm)
+ virObjectUnlock(vm);
+ return ret;
+}
+
static int
bhyveDomainOpenConsole(virDomainPtr dom,
const char *dev_name ATTRIBUTE_UNUSED,
.domainCreateWithFlags = bhyveDomainCreateWithFlags, /* 1.2.3 */
.domainCreateXML = bhyveDomainCreateXML, /* 1.2.4 */
.domainDestroy = bhyveDomainDestroy, /* 1.2.2 */
+ .domainShutdown = bhyveDomainShutdown, /* 1.3.3 */
.domainLookupByUUID = bhyveDomainLookupByUUID, /* 1.2.2 */
.domainLookupByName = bhyveDomainLookupByName, /* 1.2.2 */
.domainLookupByID = bhyveDomainLookupByID, /* 1.2.3 */
return ret;
}
+int
+virBhyveProcessShutdown(virDomainObjPtr vm)
+{
+ if (vm->pid <= 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Invalid PID %d for VM"),
+ (int)vm->pid);
+ return -1;
+ }
+
+ /* Bhyve tries to perform ACPI shutdown when it receives
+ * SIGTERM signal. So we just issue SIGTERM here and rely
+ * on the bhyve monitor to clean things up if process disappears.
+ */
+ if (virProcessKill(vm->pid, SIGTERM) != 0) {
+ VIR_WARN("Failed to terminate bhyve process for VM '%s': %s",
+ vm->def->name, virGetLastErrorMessage());
+ return -1;
+ }
+
+ return 0;
+}
+
int
virBhyveGetDomainTotalCpuStats(virDomainObjPtr vm,
unsigned long long *cpustats)
virDomainObjPtr vm,
virDomainShutoffReason reason);
+int virBhyveProcessShutdown(virDomainObjPtr vm);
+
int virBhyveGetDomainTotalCpuStats(virDomainObjPtr vm,
unsigned long long *cpustats);