예제 #1
0
파일: handle.c 프로젝트: myyyy/libguestfs
int
guestfs_impl_set_backend_setting (guestfs_h *g, const char *name, const char *value)
{
  char *new_setting;
  size_t len;

  new_setting = safe_asprintf (g, "%s=%s", name, value);

  if (g->backend_settings == NULL) {
    g->backend_settings = safe_malloc (g, sizeof (char *));
    g->backend_settings[0] = NULL;
    len = 0;
  }
  else {
    ignore_value (guestfs_clear_backend_setting (g, name));
    len = guestfs_int_count_strings (g->backend_settings);
  }

  g->backend_settings =
    safe_realloc (g, g->backend_settings, (len+2) * sizeof (char *));
  g->backend_settings[len++] = new_setting;
  g->backend_settings[len++] = NULL;

  return 0;
}
예제 #2
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;
}