Ejemplo n.º 1
0
static inline int
wait_domain(const char *vm_name, virConnectPtr vp, int timeout)
{
	int tries = 0;
	int response = 1;
	int ret;
	virDomainPtr vdp;
	virDomainInfo vdi;
	int uuid_check;

	uuid_check = is_uuid(vm_name);

	if (uuid_check) {
		vdp = virDomainLookupByUUIDString(vp, (const char *)vm_name);
	} else {
		vdp = virDomainLookupByName(vp, vm_name);
	}
	if (!vdp)
		return 0;

	/* Check domain liveliness.  If the domain is still here,
	   we return failure, and the client must then retry */
	/* XXX On the xen 3.0.4 API, we will be able to guarantee
	   synchronous virDomainDestroy, so this check will not
	   be necessary */
	do {
		if (++tries > timeout)
			break;

		sleep(1);
		if (uuid_check) {
			vdp = virDomainLookupByUUIDString(vp, (const char *)vm_name);
		} else {
			vdp = virDomainLookupByName(vp, vm_name);
		}
		if (!vdp) {
			dbg_printf(2, "Domain no longer exists\n");
			response = 0;
			break;
		}

		memset(&vdi, 0, sizeof(vdi));
		ret = virDomainGetInfo(vdp, &vdi);
		virDomainFree(vdp);
		if (ret < 0)
			continue;

		if (vdi.state == VIR_DOMAIN_SHUTOFF) {
			dbg_printf(2, "Domain has been shut off\n");
			response = 0;
			break;
		}

		dbg_printf(4, "Domain still exists (state %d) after %d seconds\n",
			vdi.state, tries);
	} while (1);

	return response;
}
Ejemplo n.º 2
0
static int
libvirt_status(const char *vm_name, void *priv)
{
	struct libvirt_info *info = (struct libvirt_info *)priv;
	virDomainPtr vdp;
	virDomainInfo vdi;
	int ret = 0;

	dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
	VALIDATE(info);

	if (is_uuid(vm_name)) {
		vdp = virDomainLookupByUUIDString(info->vp,
					    (const char *)vm_name);
	} else {
		vdp = virDomainLookupByName(info->vp, vm_name);
	}

	if (!vdp || ((virDomainGetInfo(vdp, &vdi) == 0) &&
	     (vdi.state == VIR_DOMAIN_SHUTOFF))) {
		ret = RESP_OFF;
	}

	if (vdp)
		virDomainFree(vdp);
	return ret;
}
Ejemplo n.º 3
0
static int
libvirt_off(const char *vm_name, const char *src,
	    uint32_t seqno, void *priv)
{
	struct libvirt_info *info = (struct libvirt_info *)priv;
	virDomainPtr vdp;
	virDomainInfo vdi;
	int ret = -1;

	dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
	VALIDATE(info);

	if (is_uuid(vm_name)) {
		vdp = virDomainLookupByUUIDString(info->vp,
					    (const char *)vm_name);
	} else {
		vdp = virDomainLookupByName(info->vp, vm_name);
	}

	if (!vdp) {
		dbg_printf(2, "Nothing to do - domain does not exist\n");
		return 1;
	}

	if (((virDomainGetInfo(vdp, &vdi) == 0) &&
	     (vdi.state == VIR_DOMAIN_SHUTOFF))) {
		dbg_printf(2, "Nothing to do - domain is off\n");
		virDomainFree(vdp);
		return 0;
	}

	syslog(LOG_NOTICE, "Destroying domain %s\n", vm_name);
	dbg_printf(2, "[OFF] Calling virDomainDestroy\n");
	ret = virDomainDestroy(vdp);
	if (ret < 0) {
		syslog(LOG_NOTICE, "Failed to destroy domain: %d\n", ret);
		printf("virDomainDestroy() failed: %d\n", ret);
		return 1;
	}

	if (ret) {
		syslog(LOG_NOTICE,
		       "Domain %s still exists; fencing failed\n",
		       vm_name);
		printf("Domain %s still exists; fencing failed\n", vm_name);
		return 1;
	}

	return 0;
}
Ejemplo n.º 4
0
static int
libvirt_on(const char *vm_name, const char *src,
	   uint32_t seqno, void *priv)
{
	struct libvirt_info *info = (struct libvirt_info *)priv;
	virDomainPtr vdp;
	virDomainInfo vdi;
	int ret = -1;

	dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
	VALIDATE(info);

	if (is_uuid(vm_name)) {
		vdp = virDomainLookupByUUIDString(info->vp,
					    (const char *)vm_name);
	} else {
		vdp = virDomainLookupByName(info->vp, vm_name);
	}

	if (vdp &&
	    ((virDomainGetInfo(vdp, &vdi) == 0) &&
	     (vdi.state != VIR_DOMAIN_SHUTOFF))) {
		dbg_printf(2, "Nothing to do - domain is running\n");

		if (vdp)
			virDomainFree(vdp);
		return 0;
	}

	syslog(LOG_NOTICE, "Starting domain %s\n", vm_name);
	dbg_printf(2, "[ON] Calling virDomainCreate\n");
	ret = virDomainCreate(vdp);
	if (ret < 0) {
		syslog(LOG_NOTICE, "Failed to start domain: %d\n", ret);
		printf("virDomainCreate() failed: %d\n", ret);
		return 1;
	}

	if (ret) {
		syslog(LOG_NOTICE,
		       "Domain %s did not start\n",
		       vm_name);
		printf("Domain %s did not start\n", vm_name);
		return 1;
	}
	syslog(LOG_NOTICE, "Domain %s started\n", vm_name);

	return 0;
}
Ejemplo n.º 5
0
int
guestfs_impl_add_domain (guestfs_h *g, const char *domain_name,
                     const struct guestfs_add_domain_argv *optargs)
{
  virErrorPtr err;
  virConnectPtr conn = NULL;
  virDomainPtr dom = NULL;
  int r = -1;
  const char *libvirturi;
  int readonly;
  int live;
  int allowuuid;
  const char *readonlydisk;
  const char *iface;
  const char *cachemode;
  const char *discard;
  bool copyonread;
  struct guestfs_add_libvirt_dom_argv optargs2 = { .bitmask = 0 };

  libvirturi = optargs->bitmask & GUESTFS_ADD_DOMAIN_LIBVIRTURI_BITMASK
               ? optargs->libvirturi : NULL;
  readonly = optargs->bitmask & GUESTFS_ADD_DOMAIN_READONLY_BITMASK
             ? optargs->readonly : 0;
  iface = optargs->bitmask & GUESTFS_ADD_DOMAIN_IFACE_BITMASK
          ? optargs->iface : NULL;
  live = optargs->bitmask & GUESTFS_ADD_DOMAIN_LIVE_BITMASK
         ? optargs->live : 0;
  allowuuid = optargs->bitmask & GUESTFS_ADD_DOMAIN_ALLOWUUID_BITMASK
            ? optargs->allowuuid : 0;
  readonlydisk = optargs->bitmask & GUESTFS_ADD_DOMAIN_READONLYDISK_BITMASK
               ? optargs->readonlydisk : NULL;
  cachemode = optargs->bitmask & GUESTFS_ADD_DOMAIN_CACHEMODE_BITMASK
            ? optargs->cachemode : NULL;
  discard = optargs->bitmask & GUESTFS_ADD_DOMAIN_DISCARD_BITMASK
          ? optargs->discard : NULL;
  copyonread = optargs->bitmask & GUESTFS_ADD_DOMAIN_COPYONREAD_BITMASK
               ? optargs->copyonread : false;

  if (live && readonly) {
    error (g, _("you cannot set both live and readonly flags"));
    return -1;
  }

  /* Connect to libvirt, find the domain. */
  conn = guestfs_int_open_libvirt_connection (g, libvirturi, VIR_CONNECT_RO);
  if (!conn) {
    err = virGetLastError ();
    error (g, _("could not connect to libvirt (code %d, domain %d): %s"),
           err->code, err->domain, err->message);
    goto cleanup;
  }

  /* Suppress default behaviour of printing errors to stderr.  Note
   * you can't set this to NULL to ignore errors; setting it to NULL
   * restores the default error handler ...
   */
  virConnSetErrorFunc (conn, NULL, ignore_errors);

  /* Try UUID first. */
  if (allowuuid)
    dom = virDomainLookupByUUIDString (conn, domain_name);

  /* Try ordinary domain name. */
  if (!dom)
    dom = virDomainLookupByName (conn, domain_name);

  if (!dom) {
    err = virGetLastError ();
    error (g, _("no libvirt domain called '%s': %s"),
           domain_name, err->message);
    goto cleanup;
  }

  if (readonly) {
    optargs2.bitmask |= GUESTFS_ADD_LIBVIRT_DOM_READONLY_BITMASK;
    optargs2.readonly = readonly;
  }
  if (iface) {
    optargs2.bitmask |= GUESTFS_ADD_LIBVIRT_DOM_IFACE_BITMASK;
    optargs2.iface = iface;
  }
  if (live) {
    optargs2.bitmask |= GUESTFS_ADD_LIBVIRT_DOM_LIVE_BITMASK;
    optargs2.live = live;
  }
  if (readonlydisk) {
    optargs2.bitmask |= GUESTFS_ADD_LIBVIRT_DOM_READONLYDISK_BITMASK;
    optargs2.readonlydisk = readonlydisk;
  }
  if (cachemode) {
    optargs2.bitmask |= GUESTFS_ADD_LIBVIRT_DOM_CACHEMODE_BITMASK;
    optargs2.cachemode = cachemode;
  }
  if (discard) {
    optargs2.bitmask |= GUESTFS_ADD_LIBVIRT_DOM_DISCARD_BITMASK;
    optargs2.discard = discard;
  }
  if (copyonread) {
    optargs2.bitmask |= GUESTFS_ADD_LIBVIRT_DOM_COPYONREAD_BITMASK;
    optargs2.copyonread = copyonread;
  }

  r = guestfs_add_libvirt_dom_argv (g, dom, &optargs2);

 cleanup:
  if (dom) virDomainFree (dom);
  if (conn) virConnectClose (conn);

  return r;
}

static int add_disk (guestfs_h *g, const char *filename, const char *format, int readonly, const char *protocol, char *const *server, const char *username, void *data);
static int connect_live (guestfs_h *g, virDomainPtr dom);

enum readonlydisk {
  readonlydisk_error,
  readonlydisk_read,
  readonlydisk_write,
  readonlydisk_ignore,
};

struct add_disk_data {
  int readonly;
  enum readonlydisk readonlydisk;
  /* Other args to pass through to add_drive_opts. */
  struct guestfs_add_drive_opts_argv optargs;
};

int
guestfs_impl_add_libvirt_dom (guestfs_h *g, void *domvp,
                          const struct guestfs_add_libvirt_dom_argv *optargs)
{
  virDomainPtr dom = domvp;
  ssize_t r;
  int readonly;
  const char *iface;
  const char *cachemode;
  const char *discard;
  bool copyonread;
  int live;
  /* Default for back-compat reasons: */
  enum readonlydisk readonlydisk = readonlydisk_write;
  size_t ckp;
  struct add_disk_data data;
  CLEANUP_XMLFREEDOC xmlDocPtr doc = NULL;
  CLEANUP_FREE char *label = NULL, *imagelabel = NULL;

  readonly =
    optargs->bitmask & GUESTFS_ADD_LIBVIRT_DOM_READONLY_BITMASK
    ? optargs->readonly : 0;
  iface =
    optargs->bitmask & GUESTFS_ADD_LIBVIRT_DOM_IFACE_BITMASK
    ? optargs->iface : NULL;
  live =
    optargs->bitmask & GUESTFS_ADD_LIBVIRT_DOM_LIVE_BITMASK
    ? optargs->live : 0;

  if ((optargs->bitmask & GUESTFS_ADD_LIBVIRT_DOM_READONLYDISK_BITMASK)) {
    if (STREQ (optargs->readonlydisk, "error"))
      readonlydisk = readonlydisk_error;
    else if (STREQ (optargs->readonlydisk, "read"))
      readonlydisk = readonlydisk_read;
    else if (STREQ (optargs->readonlydisk, "write"))
      readonlydisk = readonlydisk_write;
    else if (STREQ (optargs->readonlydisk, "ignore"))
      readonlydisk = readonlydisk_ignore;
    else {
      error (g, _("unknown readonlydisk parameter"));
      return -1;
    }
  }

  cachemode =
    optargs->bitmask & GUESTFS_ADD_LIBVIRT_DOM_CACHEMODE_BITMASK
    ? optargs->cachemode : NULL;

  discard =
    optargs->bitmask & GUESTFS_ADD_LIBVIRT_DOM_DISCARD_BITMASK
    ? optargs->discard : NULL;

  copyonread =
    optargs->bitmask & GUESTFS_ADD_LIBVIRT_DOM_COPYONREAD_BITMASK
    ? optargs->copyonread : false;

  if (live && readonly) {
    error (g, _("you cannot set both live and readonly flags"));
    return -1;
  }

  if (!readonly) {
    virDomainInfo info;
    virErrorPtr err;
    int vm_running;

    if (virDomainGetInfo (dom, &info) == -1) {
      err = virGetLastError ();
      error (g, _("error getting domain info: %s"), err->message);
      return -1;
    }
    vm_running = info.state != VIR_DOMAIN_SHUTOFF;

    if (vm_running) {
      /* If the caller specified the 'live' flag, then they want us to
       * try to connect to guestfsd if the domain is running.  Note
       * that live readonly connections are not possible.
       */
      if (live)
        return connect_live (g, dom);

      /* Dangerous to modify the disks of a running VM. */
      error (g, _("error: domain is a live virtual machine.\n"
                  "Writing to the disks of a running virtual machine can cause disk corruption.\n"
                  "Either use read-only access, or if the guest is running the guestfsd daemon\n"
                  "specify live access.  In most libguestfs tools these options are --ro or\n"
                  "--live respectively.  Consult the documentation for further information."));
      return -1;
    }
  }

  /* Domain XML. */
  if ((doc = get_domain_xml (g, dom)) == NULL)
    return -1;

  /* Find and pass the SELinux security label to the libvirt back end.
   * Note this has to happen before adding the disks, since those may
   * use the label.
   */
  if (libvirt_selinux_label (g, doc, &label, &imagelabel) == -1)
    return -1;
  if (label && imagelabel) {
    guestfs_set_backend_setting (g, "internal_libvirt_label", label);
    guestfs_set_backend_setting (g, "internal_libvirt_imagelabel", imagelabel);
    guestfs_set_backend_setting (g, "internal_libvirt_norelabel_disks", "1");
  }
  else
    guestfs_clear_backend_setting (g, "internal_libvirt_norelabel_disks");

  /* Add the disks. */
  data.optargs.bitmask = 0;
  data.readonly = readonly;
  data.readonlydisk = readonlydisk;
  if (iface) {
    data.optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_IFACE_BITMASK;
    data.optargs.iface = iface;
  }
  if (cachemode) {
    data.optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_CACHEMODE_BITMASK;
    data.optargs.cachemode = cachemode;
  }
  if (discard) {
    data.optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_DISCARD_BITMASK;
    data.optargs.discard = discard;
  }
  if (copyonread) {
    data.optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_COPYONREAD_BITMASK;
    data.optargs.copyonread = copyonread;
  }

  /* Checkpoint the command line around the operation so that either
   * all disks are added or none are added.
   */
  ckp = guestfs_int_checkpoint_drives (g);
  r = for_each_disk (g, doc, add_disk, &data);
  if (r == -1)
    guestfs_int_rollback_drives (g, ckp);

  return r;
}
Ejemplo n.º 6
0
void NodeWrap::syncDomains()
{
    /* Sync up with domains that are defined but not active. */
    int maxname = virConnectNumOfDefinedDomains(conn);
    if (maxname < 0) {
        REPORT_ERR(conn, "virConnectNumOfDefinedDomains");
        return;
    } else {
        char **dnames;
        dnames = (char **) malloc(sizeof(char *) * maxname);

        if ((maxname = virConnectListDefinedDomains(conn, dnames, maxname)) < 0) {
            REPORT_ERR(conn, "virConnectListDefinedDomains");
            free(dnames);
            return;
        }


        for (int i = 0; i < maxname; i++) {
            virDomainPtr domain_ptr;

            bool found = false;
            for (std::vector<DomainWrap*>::iterator iter = domains.begin();
                    iter != domains.end(); iter++) {
                if ((*iter)->domain_name == dnames[i]) {
                    found = true;
                    break;
                }
            }

            if (found) {
                continue;
            }

            domain_ptr = virDomainLookupByName(conn, dnames[i]);
            if (!domain_ptr) {
                REPORT_ERR(conn, "virDomainLookupByName");
            } else {
                DomainWrap *domain;
                try {
                    domain = new DomainWrap(agent, this, domain_ptr, conn);
                    printf("Created new domain: %s, ptr is %p\n", dnames[i], domain_ptr);
                    domains.push_back(domain);
                } catch (int i) {
                    printf ("Error constructing domain\n");
                    REPORT_ERR(conn, "constructing domain.");
                    delete domain;
                }
            }
        }
        for (int i = 0; i < maxname; i++) {
            free(dnames[i]);
        }

        free(dnames);
    }

    /* Go through all the active domains */
    int maxids = virConnectNumOfDomains(conn);
    if (maxids < 0) {
        REPORT_ERR(conn, "virConnectNumOfDomains");
        return;
    } else {
        int *ids;
        ids = (int *) malloc(sizeof(int *) * maxids);

        if ((maxids = virConnectListDomains(conn, ids, maxids)) < 0) {
            printf("Error getting list of defined domains\n");
            return;
        }

        for (int i = 0; i < maxids; i++) {
            virDomainPtr domain_ptr;
            char dom_uuid[VIR_UUID_STRING_BUFLEN];

            domain_ptr = virDomainLookupByID(conn, ids[i]);
            if (!domain_ptr) {
                REPORT_ERR(conn, "virDomainLookupByID");
                continue;
            }

            if (virDomainGetUUIDString(domain_ptr, dom_uuid) < 0) {
                REPORT_ERR(conn, "virDomainGetUUIDString");
                continue;
            }

            bool found = false;
            for (std::vector<DomainWrap*>::iterator iter = domains.begin();
                    iter != domains.end(); iter++) {
                if (strcmp((*iter)->domain_uuid.c_str(), dom_uuid) == 0) {
                    found = true;
                    break;
                }
            }

            if (found) {
                virDomainFree(domain_ptr);
                continue;
            }

            DomainWrap *domain;
            try {
                domain = new DomainWrap(agent, this, domain_ptr, conn);
                printf("Created new domain: %d, ptr is %p\n", ids[i], domain_ptr);
                domains.push_back(domain);
            } catch (int i) {
                printf ("Error constructing domain\n");
                REPORT_ERR(conn, "constructing domain.");
                delete domain;
            }
        }

        free(ids);
    }

    /* Go through our list of domains and ensure that they still exist. */
    for (std::vector<DomainWrap*>::iterator iter = domains.begin(); iter != domains.end();) {

        printf("verifying domain %s\n", (*iter)->domain_name.c_str());
        virDomainPtr ptr = virDomainLookupByUUIDString(conn, (*iter)->domain_uuid.c_str());
        if (ptr == NULL) {
            REPORT_ERR(conn, "virDomainLookupByUUIDString");
            delete (*iter);
            iter = domains.erase(iter);
        } else {
            virDomainFree(ptr);
            iter++;
        }
    }
}
Ejemplo n.º 7
0
static int
libvirt_reboot(const char *vm_name, const char *src,
	       uint32_t seqno, void *priv)
{
	struct libvirt_info *info = (struct libvirt_info *)priv;
	virDomainPtr vdp, nvdp;
	virDomainInfo vdi;
	char *domain_desc;
	int ret;

	//uuid_unparse(vm_uuid, uu_string);
	dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
	VALIDATE(info);
	
	if (is_uuid(vm_name)) {
		vdp = virDomainLookupByUUIDString(info->vp,
					    (const char *)vm_name);
	} else {
		vdp = virDomainLookupByName(info->vp, vm_name);
	}

	if (!vdp) {
		dbg_printf(2, "[libvirt:REBOOT] Nothing to "
			   "do - domain does not exist\n");
		return 1;
	}

	if (((virDomainGetInfo(vdp, &vdi) == 0) &&
	     (vdi.state == VIR_DOMAIN_SHUTOFF))) {
			dbg_printf(2, "[libvirt:REBOOT] Nothing to "
				   "do - domain is off\n");
		virDomainFree(vdp);
		return 0;
	}


	syslog(LOG_NOTICE, "Rebooting domain %s\n", vm_name);
	printf("Rebooting domain %s...\n", vm_name);
	domain_desc = virDomainGetXMLDesc(vdp, 0);

	if (!domain_desc) {
		printf("Failed getting domain description from "
		       "libvirt\n");
	}

	dbg_printf(2, "[REBOOT] Calling virDomainDestroy(%p)\n", vdp);
	ret = virDomainDestroy(vdp);
	if (ret < 0) {
		printf("virDomainDestroy() failed: %d/%d\n", ret, errno);
		free(domain_desc);
		virDomainFree(vdp);
		return 1;
	}

	ret = wait_domain(vm_name, info->vp, 15);

	if (ret) {
		syslog(LOG_NOTICE, "Domain %s still exists; fencing failed\n",
		       vm_name);
		printf("Domain %s still exists; fencing failed\n", vm_name);
		if (domain_desc)
			free(domain_desc);
		return 1;
	}
		
	if (!domain_desc)
		return 0;

	/* 'on' is not a failure */
	ret = 0;

	dbg_printf(3, "[[ XML Domain Info ]]\n");
	dbg_printf(3, "%s\n[[ XML END ]]\n", domain_desc);
	dbg_printf(2, "Calling virDomainCreateLinux()...\n");

	nvdp = virDomainCreateLinux(info->vp, domain_desc, 0);
	if (nvdp == NULL) {
		/* More recent versions of libvirt or perhaps the
		 * KVM back-end do not let you create a domain from
		 * XML if there is already a defined domain description
		 * with the same name that it knows about.  You must
		 * then call virDomainCreate() */
		dbg_printf(2, "Failed; Trying virDomainCreate()...\n");
		if (virDomainCreate(vdp) < 0) {
			syslog(LOG_NOTICE,
			       "Could not restart %s\n",
			       vm_name);
			dbg_printf(1, "Failed to recreate guest"
				   " %s!\n", vm_name);
		}
	}

	free(domain_desc);

	return ret;
}
Ejemplo n.º 8
0
void run(char *myIP, virConnectPtr localhost) {

	printf("*** New run\n");
	virDomainPtr *domains, *domainsptr;
	virConnectListAllDomains(localhost, &domains, VIR_CONNECT_LIST_DOMAINS_ACTIVE|VIR_CONNECT_LIST_DOMAINS_INACTIVE|VIR_CONNECT_LIST_DOMAINS_RUNNING|VIR_CONNECT_LIST_DOMAINS_SHUTOFF);
	domainsptr = domains;
	char **domainuuids = malloc(sizeof(char*)*1024);
	char **domainuuidsptr = domainuuids;
	*domainuuids = NULL;
	printf("Domains\n");
	while(*domainsptr != NULL) {
		char buf[VIR_UUID_STRING_BUFLEN];
		virDomainGetUUIDString(*domainsptr, buf);
		const char *name = virDomainGetName(*domainsptr);
		if (!strncmp("ignore",name,strlen("ignore"))) {
			domainsptr++;
			continue;
		}
		printf("%s\n", buf);
		*(domainuuidsptr++) = strdup(buf);
		*domainuuidsptr = NULL;
		domainsptr++;
	}
	domainuuidsptr = domainuuids;
	size_t domainuuids_count=0;
	while(*domainuuidsptr != NULL) domainuuidsptr++, domainuuids_count++;
	domainuuidsptr = domainuuids;
	domainsptr = domains;
	char **hosts = gethosts();
	char **hostsptr=hosts;
	size_t hosts_count = 0;
	while (*hostsptr != NULL) hosts_count++, hostsptr++;
	hostsptr = hosts;
	struct hostwithvmhash **cs = malloc(sizeof(struct hostwithvmhash)*1024);
	*cs = NULL;
	struct hostwithvmhash **csptr = cs;
	int sign=0;
	while(*hostsptr != NULL) {
		if (!strcmp(*hostsptr, myIP)) printf("ME! ");
		sign = !sign;
		size_t k=1;
		while(*domainuuidsptr != NULL) {
/*			char *num = "$6$hest";
			char *hash = crypt(*domainuuidsptr, num);
			char *hash2 = crypt(*hostsptr, num);*/
			struct hostwithvmhash *c=malloc(sizeof(struct hostwithvmhash));
			c->host = *hostsptr;
//			c->host_hash = strdup(hash+10);
			c->vm = *domainuuidsptr;
//			c->vm_hash = strdup(hash2+10);
			c->combined = malloc(10000);
			strcpy(c->combined, "");
			strcat(c->combined, c->host);
			strcat(c->combined, c->vm);
			//c->combined = strdup(crypt(c->combined, num));


			*(csptr++) = c;
			*csptr = NULL;

			domainuuidsptr++;
		}
		domainuuidsptr = domainuuids;
		printf("%s\n", *hostsptr);
	/*	char URL[512];
		sprintf(URL, "qemu+ssh://%s/system", *hosts);
		virConnectPtr dest = virConnectOpen(URL);
		*(destsptr++) = dest;
		*destsptr = NULL;*/
		hostsptr++;
	}
	csptr = cs;
	
	printf("\n");

	size_t count=0;
	while(*csptr != NULL) count++, csptr++;
	csptr = cs;

	qsort(csptr, count, sizeof(struct hostwithvmhash*), (__compar_fn_t)cscompare);

	struct hostwithvmhash **csptrptr = csptr;
	size_t i=0,k=0,j=0,q=1,m=0;
	char *last_host=NULL,*last_vm=NULL;
	struct hostwithvmhash **seen=malloc(sizeof(struct hostwithvmhash*)*1024);
	*seen = NULL;
	struct hostwithvmhash **seenptr=seen;
	struct hostwithvmhash **seenaddptr=seen;
	while(*csptrptr != NULL) {
		if (last_host == NULL || strcmp(last_host, (*csptrptr)->host))
			last_host = (*csptrptr)->host,k++;
		
		seenptr=seen;
		int is_seen=0;
		while(*seenptr != NULL) {
			if (!strcmp((*seenptr)->vm, (*csptrptr)->vm))
				is_seen=1;
			seenptr++;
		}
		if (!is_seen) {
			m++,*(seenaddptr++) = *csptrptr, *seenaddptr = NULL;
			(*csptrptr)->prio = 100*m+(k+m)%hosts_count;
			if (m == domainuuids_count)
				m = 0, seenaddptr=seenptr=seen,*seen=NULL;
		} else
			(*csptrptr)->prio = k;
		csptrptr++;
	}
	qsort(csptr, count, sizeof(struct hostwithvmhash*), (__compar_fn_t)cscompareprio);

	struct hostwithvmhash **cleaned = cleanlist(csptr);
	struct hostwithvmhash **cleanedstart = cleaned;

	while(*cleaned != NULL) {
		virDomainPtr d = virDomainLookupByUUIDString(localhost, (*cleaned)->vm);
		const char *name = virDomainGetName(d);
		int state, reason;
		virDomainGetState(d, &state, &reason, 0);
		if (!strcmp((*cleaned)->host, myIP)) {
			printf("I should be running %s (%s)\n", name, (*cleaned)->vm);
			if (state == VIR_DOMAIN_RUNNING)
				printf("...and it's running.\n");
			else
				virDomainCreate(d);
		} else {
			printf("I should NOT be running %s (%s)\n", name, (*cleaned)->vm);
			if (state == VIR_DOMAIN_RUNNING) {
				printf("Destroying.\n");
				virDomainDestroy(d);
			} else
				printf("...and it's not running.\n");
		}
		if (d) {
			virDomainFree(d);
		}
		//printf("prio:%d host:%s, vm:%s combined:%s\n", (*cleaned)->prio, (*cleaned)->host, (*cleaned)->vm, (*cleaned)->combined);
		cleaned++;
	}
	domainuuidsptr = domainuuids;
	while(*domainuuidsptr != NULL) {
		free(*domainuuidsptr);
		domainuuidsptr++;
	}
	free(domainuuids);
	free(cleanedstart);
	csptr = cs;
	while(*csptr != NULL) {
		free((*csptr)->combined);
		free(*csptr);
		csptr++;
	}
	free(cs);
	free(seen);
	hostsptr = hosts;
	while(*hostsptr != NULL) {
		free(*hostsptr);
		hostsptr++;
	}
	free(hosts);
	domainsptr = domains;
	while(*domainsptr != NULL) {
		virDomainFree(*domainsptr);
		domainsptr++;
	}
	free(domains);
/*
	virDomainPtr *domains;
	virConnectListAllDomains(src, &domains, VIR_CONNECT_LIST_DOMAINS_ACTIVE);
	while(*domains != NULL) {
		char *config = virDomainGetXMLDesc(*domains, 0);
		char uuid[VIR_UUID_BUFLEN];
		char uuidstr[VIR_UUID_STRING_BUFLEN];
		virDomainGetUUIDString(*domains, uuidstr);
		virDomainGetUUID(*domains, uuid);
		destsptr = dests;
		while (*destsptr != NULL) {
			virConnectPtr dest = *destsptr;
			virDomainPtr d = virDomainLookupByUUID(dest, uuid);
			if (d)
				printf("%s already in dest\n", uuidstr);
			if (!d) {
				printf("%s\n", config);
				printf("Injecting domain on dest\n");
				virDomainPtr new = virDomainDefineXML(dest, config);
			}
			fflush(stdout);
			destsptr++;
		}
		domains++;
	}*/
}