func: void qmp_drive_backup(const char *device, const char *target,
  
                        bool has_format, const char *format,
  
                        enum MirrorSyncMode sync,
  
                        bool has_mode, enum NewImageMode mode,
  
                        bool has_speed, int64_t speed,
  
                        bool has_on_source_error, BlockdevOnError on_source_error,
  
                        bool has_on_target_error, BlockdevOnError on_target_error,
  
                        Error **errp)
  
  {
  
      BlockDriverState *bs;
  
      BlockDriverState *target_bs;
  
      BlockDriverState *source = NULL;
  
      BlockDriver *drv = NULL;
  
      Error *local_err = NULL;
  
      int flags;
  
      int64_t size;
  
      int ret;
  
  
  
      if (!has_speed) {
  
          speed = 0;
  
      }
  
      if (!has_on_source_error) {
  
          on_source_error = BLOCKDEV_ON_ERROR_REPORT;
  
      }
  
      if (!has_on_target_error) {
  
          on_target_error = BLOCKDEV_ON_ERROR_REPORT;
  
      }
  
      if (!has_mode) {
  
          mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
  
      }
  
  
  
      bs = bdrv_find(device);
  
      if (!bs) {
  
          error_set(errp, QERR_DEVICE_NOT_FOUND, device);
  
          return;
  
      }
  
  
  
      if (!bdrv_is_inserted(bs)) {
  
          error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
  
          return;
  
      }
  
  
  
      if (!has_format) {
  
          format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
  
      }
  
      if (format) {
  
          drv = bdrv_find_format(format);
  
          if (!drv) {
  
              error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
  
              return;
  
          }
  
      }
  
  
  
      if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
  
          return;
  
      }
  
  
  
      flags = bs->open_flags | BDRV_O_RDWR;
  
  
  
      /* See if we have a backing HD we can use to create our new image
  
       * on top of. */
  
      if (sync == MIRROR_SYNC_MODE_TOP) {
  
          source = bs->backing_hd;
  
          if (!source) {
  
              sync = MIRROR_SYNC_MODE_FULL;
  
          }
  
      }
  
      if (sync == MIRROR_SYNC_MODE_NONE) {
  
          source = bs;
  
      }
  
  
  
      size = bdrv_getlength(bs);
  
      if (size < 0) {
  
          error_setg_errno(errp, -size, "bdrv_getlength failed");
  
          return;
  
      }
  
  
  
      if (mode != NEW_IMAGE_MODE_EXISTING) {
  
          assert(format && drv);
  
          if (source) {
  
              bdrv_img_create(target, format, source->filename,
  
                              source->drv->format_name, NULL,
  
                              size, flags, &local_err, false);
  
          } else {
  
              bdrv_img_create(target, format, NULL, NULL, NULL,
  
                              size, flags, &local_err, false);
  
          }
  
      }
  
  
  
      if (local_err) {
  
          error_propagate(errp, local_err);
  
          return;
  
      }
  
  
  
      target_bs = NULL;
  
      ret = bdrv_open(&target_bs, target, NULL, NULL, flags, drv, &local_err);
  
      if (ret < 0) {
  
          error_propagate(errp, local_err);
  
          return;
  
      }
  
  
  
      backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
  
                   block_job_cb, bs, &local_err);
  
      if (local_err != NULL) {
  
          bdrv_unref(target_bs);
  
          error_propagate(errp, local_err);
  
          return;
  
      }
  
  }
  