Merge remote-tracking branch 'qmp/queue/qmp' into staging

* qmp/queue/qmp:
  block: use proper qerrors in qmp_block_resize
  qerror: restore alphabetical order over qerrors
  qerror: add check-qerror.sh to verify alphabetical order
  qmp: Add missing gcc format attribute and fix format string
  qapi: Convert block_set_io_throttle
  qapi: Convert change
  qerror: Extend QERR_DEVICE_ENCRYPTED
  qapi: Introduce change-vnc-password
  monitor: expose readline state
  qapi: Convert eject
  block: eject_device(): Use error_set()
  qapi: Convert expire_password
  qapi: Convert set_password
  vnc: Simplify vnc_display_password()
This commit is contained in:
Anthony Liguori 2012-01-19 09:23:16 -06:00
commit b48c0134de
16 changed files with 657 additions and 371 deletions

View File

@ -665,35 +665,35 @@ void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file,
} }
} }
static int eject_device(Monitor *mon, BlockDriverState *bs, int force) static void eject_device(BlockDriverState *bs, int force, Error **errp)
{ {
if (!bdrv_dev_has_removable_media(bs)) { if (!bdrv_dev_has_removable_media(bs)) {
qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs)); error_set(errp, QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
return -1; return;
} }
if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) { if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
bdrv_dev_eject_request(bs, force); bdrv_dev_eject_request(bs, force);
if (!force) { if (!force) {
qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs)); error_set(errp, QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
return -1; return;
} }
} }
bdrv_close(bs); bdrv_close(bs);
return 0;
} }
int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data) void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
{ {
BlockDriverState *bs; BlockDriverState *bs;
int force = qdict_get_try_bool(qdict, "force", 0);
const char *filename = qdict_get_str(qdict, "device");
bs = bdrv_find(filename); bs = bdrv_find(device);
if (!bs) { if (!bs) {
qerror_report(QERR_DEVICE_NOT_FOUND, filename); error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return -1; return;
} }
return eject_device(mon, bs, force);
eject_device(bs, force, errp);
} }
void qmp_block_passwd(const char *device, const char *password, Error **errp) void qmp_block_passwd(const char *device, const char *password, Error **errp)
@ -717,78 +717,87 @@ void qmp_block_passwd(const char *device, const char *password, Error **errp)
} }
} }
int do_change_block(Monitor *mon, const char *device, static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
const char *filename, const char *fmt) int bdrv_flags, BlockDriver *drv,
const char *password, Error **errp)
{
if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
error_set(errp, QERR_OPEN_FILE_FAILED, filename);
return;
}
if (bdrv_key_required(bs)) {
if (password) {
if (bdrv_set_key(bs, password) < 0) {
error_set(errp, QERR_INVALID_PASSWORD);
}
} else {
error_set(errp, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
bdrv_get_encrypted_filename(bs));
}
} else if (password) {
error_set(errp, QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
}
}
void qmp_change_blockdev(const char *device, const char *filename,
bool has_format, const char *format, Error **errp)
{ {
BlockDriverState *bs; BlockDriverState *bs;
BlockDriver *drv = NULL; BlockDriver *drv = NULL;
int bdrv_flags; int bdrv_flags;
Error *err = NULL;
bs = bdrv_find(device); bs = bdrv_find(device);
if (!bs) { if (!bs) {
qerror_report(QERR_DEVICE_NOT_FOUND, device); error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return -1; return;
} }
if (fmt) {
drv = bdrv_find_whitelisted_format(fmt); if (format) {
drv = bdrv_find_whitelisted_format(format);
if (!drv) { if (!drv) {
qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt); error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
return -1; return;
} }
} }
if (eject_device(mon, bs, 0) < 0) {
return -1; eject_device(bs, 0, &err);
if (error_is_set(&err)) {
error_propagate(errp, err);
return;
} }
bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR; bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0; bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
qerror_report(QERR_OPEN_FILE_FAILED, filename); qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp);
return -1;
}
return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
} }
/* throttling disk I/O limits */ /* throttling disk I/O limits */
int do_block_set_io_throttle(Monitor *mon, void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
const QDict *qdict, QObject **ret_data) int64_t bps_wr, int64_t iops, int64_t iops_rd,
int64_t iops_wr, Error **errp)
{ {
BlockIOLimit io_limits; BlockIOLimit io_limits;
const char *devname = qdict_get_str(qdict, "device");
BlockDriverState *bs; BlockDriverState *bs;
io_limits.bps[BLOCK_IO_LIMIT_TOTAL] bs = bdrv_find(device);
= qdict_get_try_int(qdict, "bps", -1);
io_limits.bps[BLOCK_IO_LIMIT_READ]
= qdict_get_try_int(qdict, "bps_rd", -1);
io_limits.bps[BLOCK_IO_LIMIT_WRITE]
= qdict_get_try_int(qdict, "bps_wr", -1);
io_limits.iops[BLOCK_IO_LIMIT_TOTAL]
= qdict_get_try_int(qdict, "iops", -1);
io_limits.iops[BLOCK_IO_LIMIT_READ]
= qdict_get_try_int(qdict, "iops_rd", -1);
io_limits.iops[BLOCK_IO_LIMIT_WRITE]
= qdict_get_try_int(qdict, "iops_wr", -1);
bs = bdrv_find(devname);
if (!bs) { if (!bs) {
qerror_report(QERR_DEVICE_NOT_FOUND, devname); error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return -1; return;
} }
if ((io_limits.bps[BLOCK_IO_LIMIT_TOTAL] == -1) io_limits.bps[BLOCK_IO_LIMIT_TOTAL] = bps;
|| (io_limits.bps[BLOCK_IO_LIMIT_READ] == -1) io_limits.bps[BLOCK_IO_LIMIT_READ] = bps_rd;
|| (io_limits.bps[BLOCK_IO_LIMIT_WRITE] == -1) io_limits.bps[BLOCK_IO_LIMIT_WRITE] = bps_wr;
|| (io_limits.iops[BLOCK_IO_LIMIT_TOTAL] == -1) io_limits.iops[BLOCK_IO_LIMIT_TOTAL]= iops;
|| (io_limits.iops[BLOCK_IO_LIMIT_READ] == -1) io_limits.iops[BLOCK_IO_LIMIT_READ] = iops_rd;
|| (io_limits.iops[BLOCK_IO_LIMIT_WRITE] == -1)) { io_limits.iops[BLOCK_IO_LIMIT_WRITE]= iops_wr;
qerror_report(QERR_MISSING_PARAMETER,
"bps/bps_rd/bps_wr/iops/iops_rd/iops_wr");
return -1;
}
if (!do_check_io_limits(&io_limits)) { if (!do_check_io_limits(&io_limits)) {
qerror_report(QERR_INVALID_PARAMETER_COMBINATION); error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
return -1; return;
} }
bs->io_limits = io_limits; bs->io_limits = io_limits;
@ -803,8 +812,6 @@ int do_block_set_io_throttle(Monitor *mon,
qemu_mod_timer(bs->block_timer, qemu_get_clock_ns(vm_clock)); qemu_mod_timer(bs->block_timer, qemu_get_clock_ns(vm_clock));
} }
} }
return 0;
} }
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
@ -841,11 +848,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
return 0; return 0;
} }
/*
* XXX: replace the QERR_UNDEFINED_ERROR errors with real values once the
* existing QERR_ macro mess is cleaned up. A good example for better
* error reports can be found in the qemu-img resize code.
*/
void qmp_block_resize(const char *device, int64_t size, Error **errp) void qmp_block_resize(const char *device, int64_t size, Error **errp)
{ {
BlockDriverState *bs; BlockDriverState *bs;
@ -857,12 +859,27 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
} }
if (size < 0) { if (size < 0) {
error_set(errp, QERR_UNDEFINED_ERROR); error_set(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
return; return;
} }
if (bdrv_truncate(bs, size)) { switch (bdrv_truncate(bs, size)) {
case 0:
break;
case -ENOMEDIUM:
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
break;
case -ENOTSUP:
error_set(errp, QERR_UNSUPPORTED);
break;
case -EACCES:
error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
break;
case -EBUSY:
error_set(errp, QERR_DEVICE_IN_USE, device);
break;
default:
error_set(errp, QERR_UNDEFINED_ERROR); error_set(errp, QERR_UNDEFINED_ERROR);
return; break;
} }
} }

View File

@ -11,6 +11,7 @@
#define BLOCKDEV_H #define BLOCKDEV_H
#include "block.h" #include "block.h"
#include "error.h"
#include "qemu-queue.h" #include "qemu-queue.h"
void blockdev_mark_auto_del(BlockDriverState *bs); void blockdev_mark_auto_del(BlockDriverState *bs);
@ -57,11 +58,8 @@ DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi);
DriveInfo *add_init_drive(const char *opts); DriveInfo *add_init_drive(const char *opts);
void qmp_change_blockdev(const char *device, const char *filename,
bool has_format, const char *format, Error **errp);
void do_commit(Monitor *mon, const QDict *qdict); void do_commit(Monitor *mon, const QDict *qdict);
int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_change_block(Monitor *mon, const char *device,
const char *filename, const char *fmt);
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_block_set_io_throttle(Monitor *mon,
const QDict *qdict, QObject **ret_data);
#endif #endif

View File

@ -4,7 +4,6 @@
#include "qemu-char.h" #include "qemu-char.h"
#include "qdict.h" #include "qdict.h"
#include "notify.h" #include "notify.h"
#include "qerror.h"
#include "monitor.h" #include "monitor.h"
/* keyboard/mouse support */ /* keyboard/mouse support */
@ -384,12 +383,10 @@ int vnc_display_pw_expire(DisplayState *ds, time_t expires);
#else #else
static inline int vnc_display_password(DisplayState *ds, const char *password) static inline int vnc_display_password(DisplayState *ds, const char *password)
{ {
qerror_report(QERR_FEATURE_DISABLED, "vnc");
return -ENODEV; return -ENODEV;
} }
static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires) static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
{ {
qerror_report(QERR_FEATURE_DISABLED, "vnc");
return -ENODEV; return -ENODEV;
}; };
#endif #endif

View File

@ -75,8 +75,7 @@ ETEXI
.args_type = "force:-f,device:B", .args_type = "force:-f,device:B",
.params = "[-f] device", .params = "[-f] device",
.help = "eject a removable medium (use -f to force it)", .help = "eject a removable medium (use -f to force it)",
.user_print = monitor_user_noop, .mhandler.cmd = hmp_eject,
.mhandler.cmd_new = do_eject,
}, },
STEXI STEXI
@ -108,8 +107,7 @@ ETEXI
.args_type = "device:B,target:F,arg:s?", .args_type = "device:B,target:F,arg:s?",
.params = "device filename [format]", .params = "device filename [format]",
.help = "change a removable medium, optional format", .help = "change a removable medium, optional format",
.user_print = monitor_user_noop, .mhandler.cmd = hmp_change,
.mhandler.cmd_new = do_change,
}, },
STEXI STEXI
@ -1204,8 +1202,7 @@ ETEXI
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l", .args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
.params = "device bps bps_rd bps_wr iops iops_rd iops_wr", .params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
.help = "change I/O throttle limits for a block drive", .help = "change I/O throttle limits for a block drive",
.user_print = monitor_user_noop, .mhandler.cmd = hmp_block_set_io_throttle,
.mhandler.cmd_new = do_block_set_io_throttle,
}, },
STEXI STEXI
@ -1219,8 +1216,7 @@ ETEXI
.args_type = "protocol:s,password:s,connected:s?", .args_type = "protocol:s,password:s,connected:s?",
.params = "protocol password action-if-connected", .params = "protocol password action-if-connected",
.help = "set spice/vnc password", .help = "set spice/vnc password",
.user_print = monitor_user_noop, .mhandler.cmd = hmp_set_password,
.mhandler.cmd_new = set_password,
}, },
STEXI STEXI
@ -1240,8 +1236,7 @@ ETEXI
.args_type = "protocol:s,time:s", .args_type = "protocol:s,time:s",
.params = "protocol time", .params = "protocol time",
.help = "set spice/vnc password expire-time", .help = "set spice/vnc password expire-time",
.user_print = monitor_user_noop, .mhandler.cmd = hmp_expire_password,
.mhandler.cmd_new = expire_password,
}, },
STEXI STEXI

102
hmp.c
View File

@ -681,3 +681,105 @@ void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
int64_t value = qdict_get_int(qdict, "value"); int64_t value = qdict_get_int(qdict, "value");
qmp_migrate_set_speed(value, NULL); qmp_migrate_set_speed(value, NULL);
} }
void hmp_set_password(Monitor *mon, const QDict *qdict)
{
const char *protocol = qdict_get_str(qdict, "protocol");
const char *password = qdict_get_str(qdict, "password");
const char *connected = qdict_get_try_str(qdict, "connected");
Error *err = NULL;
qmp_set_password(protocol, password, !!connected, connected, &err);
hmp_handle_error(mon, &err);
}
void hmp_expire_password(Monitor *mon, const QDict *qdict)
{
const char *protocol = qdict_get_str(qdict, "protocol");
const char *whenstr = qdict_get_str(qdict, "time");
Error *err = NULL;
qmp_expire_password(protocol, whenstr, &err);
hmp_handle_error(mon, &err);
}
void hmp_eject(Monitor *mon, const QDict *qdict)
{
int force = qdict_get_try_bool(qdict, "force", 0);
const char *device = qdict_get_str(qdict, "device");
Error *err = NULL;
qmp_eject(device, true, force, &err);
hmp_handle_error(mon, &err);
}
static void hmp_change_read_arg(Monitor *mon, const char *password,
void *opaque)
{
qmp_change_vnc_password(password, NULL);
monitor_read_command(mon, 1);
}
static void cb_hmp_change_bdrv_pwd(Monitor *mon, const char *password,
void *opaque)
{
Error *encryption_err = opaque;
Error *err = NULL;
const char *device;
device = error_get_field(encryption_err, "device");
qmp_block_passwd(device, password, &err);
hmp_handle_error(mon, &err);
error_free(encryption_err);
monitor_read_command(mon, 1);
}
void hmp_change(Monitor *mon, const QDict *qdict)
{
const char *device = qdict_get_str(qdict, "device");
const char *target = qdict_get_str(qdict, "target");
const char *arg = qdict_get_try_str(qdict, "arg");
Error *err = NULL;
if (strcmp(device, "vnc") == 0 &&
(strcmp(target, "passwd") == 0 ||
strcmp(target, "password") == 0)) {
if (!arg) {
monitor_read_password(mon, hmp_change_read_arg, NULL);
return;
}
}
qmp_change(device, target, !!arg, arg, &err);
if (error_is_type(err, QERR_DEVICE_ENCRYPTED)) {
monitor_printf(mon, "%s (%s) is encrypted.\n",
error_get_field(err, "device"),
error_get_field(err, "filename"));
if (!monitor_get_rs(mon)) {
monitor_printf(mon,
"terminal does not support password prompting\n");
error_free(err);
return;
}
readline_start(monitor_get_rs(mon), "Password: ", 1,
cb_hmp_change_bdrv_pwd, err);
return;
}
hmp_handle_error(mon, &err);
}
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
qmp_block_set_io_throttle(qdict_get_str(qdict, "device"),
qdict_get_int(qdict, "bps"),
qdict_get_int(qdict, "bps_rd"),
qdict_get_int(qdict, "bps_wr"),
qdict_get_int(qdict, "iops"),
qdict_get_int(qdict, "iops_rd"),
qdict_get_int(qdict, "iops_wr"), &err);
hmp_handle_error(mon, &err);
}

5
hmp.h
View File

@ -49,5 +49,10 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict); void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict); void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict); void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
void hmp_set_password(Monitor *mon, const QDict *qdict);
void hmp_expire_password(Monitor *mon, const QDict *qdict);
void hmp_eject(Monitor *mon, const QDict *qdict);
void hmp_change(Monitor *mon, const QDict *qdict);
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
#endif #endif

177
monitor.c
View File

@ -227,7 +227,7 @@ int monitor_cur_is_qmp(void)
return cur_mon && monitor_ctrl_mode(cur_mon); return cur_mon && monitor_ctrl_mode(cur_mon);
} }
static void monitor_read_command(Monitor *mon, int show_prompt) void monitor_read_command(Monitor *mon, int show_prompt)
{ {
if (!mon->rs) if (!mon->rs)
return; return;
@ -237,7 +237,7 @@ static void monitor_read_command(Monitor *mon, int show_prompt)
readline_show_prompt(mon->rs); readline_show_prompt(mon->rs);
} }
static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func, int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
void *opaque) void *opaque)
{ {
if (monitor_ctrl_mode(mon)) { if (monitor_ctrl_mode(mon)) {
@ -810,171 +810,6 @@ static void do_trace_print_events(Monitor *mon)
trace_print_events((FILE *)mon, &monitor_fprintf); trace_print_events((FILE *)mon, &monitor_fprintf);
} }
#ifdef CONFIG_VNC
static int change_vnc_password(const char *password)
{
if (!password || !password[0]) {
if (vnc_display_disable_login(NULL)) {
qerror_report(QERR_SET_PASSWD_FAILED);
return -1;
}
return 0;
}
if (vnc_display_password(NULL, password) < 0) {
qerror_report(QERR_SET_PASSWD_FAILED);
return -1;
}
return 0;
}
static void change_vnc_password_cb(Monitor *mon, const char *password,
void *opaque)
{
change_vnc_password(password);
monitor_read_command(mon, 1);
}
static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
{
if (strcmp(target, "passwd") == 0 ||
strcmp(target, "password") == 0) {
if (arg) {
char password[9];
strncpy(password, arg, sizeof(password));
password[sizeof(password) - 1] = '\0';
return change_vnc_password(password);
} else {
return monitor_read_password(mon, change_vnc_password_cb, NULL);
}
} else {
if (vnc_display_open(NULL, target) < 0) {
qerror_report(QERR_VNC_SERVER_FAILED, target);
return -1;
}
}
return 0;
}
#else
static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
{
qerror_report(QERR_FEATURE_DISABLED, "vnc");
return -ENODEV;
}
#endif
/**
* do_change(): Change a removable medium, or VNC configuration
*/
static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *device = qdict_get_str(qdict, "device");
const char *target = qdict_get_str(qdict, "target");
const char *arg = qdict_get_try_str(qdict, "arg");
int ret;
if (strcmp(device, "vnc") == 0) {
ret = do_change_vnc(mon, target, arg);
} else {
ret = do_change_block(mon, device, target, arg);
}
return ret;
}
static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *protocol = qdict_get_str(qdict, "protocol");
const char *password = qdict_get_str(qdict, "password");
const char *connected = qdict_get_try_str(qdict, "connected");
int disconnect_if_connected = 0;
int fail_if_connected = 0;
int rc;
if (connected) {
if (strcmp(connected, "fail") == 0) {
fail_if_connected = 1;
} else if (strcmp(connected, "disconnect") == 0) {
disconnect_if_connected = 1;
} else if (strcmp(connected, "keep") == 0) {
/* nothing */
} else {
qerror_report(QERR_INVALID_PARAMETER, "connected");
return -1;
}
}
if (strcmp(protocol, "spice") == 0) {
if (!using_spice) {
/* correct one? spice isn't a device ,,, */
qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
return -1;
}
rc = qemu_spice_set_passwd(password, fail_if_connected,
disconnect_if_connected);
if (rc != 0) {
qerror_report(QERR_SET_PASSWD_FAILED);
return -1;
}
return 0;
}
if (strcmp(protocol, "vnc") == 0) {
if (fail_if_connected || disconnect_if_connected) {
/* vnc supports "connected=keep" only */
qerror_report(QERR_INVALID_PARAMETER, "connected");
return -1;
}
/* Note that setting an empty password will not disable login through
* this interface. */
return vnc_display_password(NULL, password);
}
qerror_report(QERR_INVALID_PARAMETER, "protocol");
return -1;
}
static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *protocol = qdict_get_str(qdict, "protocol");
const char *whenstr = qdict_get_str(qdict, "time");
time_t when;
int rc;
if (strcmp(whenstr, "now") == 0) {
when = 0;
} else if (strcmp(whenstr, "never") == 0) {
when = TIME_MAX;
} else if (whenstr[0] == '+') {
when = time(NULL) + strtoull(whenstr+1, NULL, 10);
} else {
when = strtoull(whenstr, NULL, 10);
}
if (strcmp(protocol, "spice") == 0) {
if (!using_spice) {
/* correct one? spice isn't a device ,,, */
qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
return -1;
}
rc = qemu_spice_set_pw_expire(when);
if (rc != 0) {
qerror_report(QERR_SET_PASSWD_FAILED);
return -1;
}
return 0;
}
if (strcmp(protocol, "vnc") == 0) {
return vnc_display_pw_expire(NULL, when);
}
qerror_report(QERR_INVALID_PARAMETER, "protocol");
return -1;
}
static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data) static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data)
{ {
const char *protocol = qdict_get_str(qdict, "protocol"); const char *protocol = qdict_get_str(qdict, "protocol");
@ -4755,6 +4590,11 @@ static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
monitor_read_command(mon, 1); monitor_read_command(mon, 1);
} }
ReadLineState *monitor_get_rs(Monitor *mon)
{
return mon->rs;
}
int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
BlockDriverCompletionFunc *completion_cb, BlockDriverCompletionFunc *completion_cb,
void *opaque) void *opaque)
@ -4768,7 +4608,8 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
} }
if (monitor_ctrl_mode(mon)) { if (monitor_ctrl_mode(mon)) {
qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs)); qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
bdrv_get_encrypted_filename(bs));
return -1; return -1;
} }

View File

@ -6,6 +6,7 @@
#include "qerror.h" #include "qerror.h"
#include "qdict.h" #include "qdict.h"
#include "block.h" #include "block.h"
#include "readline.h"
extern Monitor *cur_mon; extern Monitor *cur_mon;
extern Monitor *default_mon; extern Monitor *default_mon;
@ -66,6 +67,10 @@ int monitor_get_cpu_index(void);
typedef void (MonitorCompletion)(void *opaque, QObject *ret_data); typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
void monitor_set_error(Monitor *mon, QError *qerror); void monitor_set_error(Monitor *mon, QError *qerror);
void monitor_read_command(Monitor *mon, int show_prompt);
ReadLineState *monitor_get_rs(Monitor *mon);
int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
void *opaque);
int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret); int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret);

View File

@ -1064,8 +1064,11 @@
# #
# Returns: nothing on success # Returns: nothing on success
# If @device is not a valid block device, DeviceNotFound # If @device is not a valid block device, DeviceNotFound
# # If @size is negative, InvalidParameterValue
# Notes: This command returns UndefinedError in a number of error conditions. # If the block device has no medium inserted, DeviceHasNoMedium
# If the block device does not support resize, Unsupported
# If the block device is read-only, DeviceIsReadOnly
# If a long-running operation is using the device, DeviceInUse
# #
# Since: 0.14.0 # Since: 0.14.0
## ##
@ -1275,3 +1278,159 @@
{ 'command': 'qom-set', { 'command': 'qom-set',
'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' }, 'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' },
'gen': 'no' } 'gen': 'no' }
##
# @set_password:
#
# Sets the password of a remote display session.
#
# @protocol: `vnc' to modify the VNC server password
# `spice' to modify the Spice server password
#
# @password: the new password
#
# @connected: #optional how to handle existing clients when changing the
# password. If nothing is specified, defaults to `keep'
# `fail' to fail the command if clients are connected
# `disconnect' to disconnect existing clients
# `keep' to maintain existing clients
#
# Returns: Nothing on success
# If Spice is not enabled, DeviceNotFound
# If @protocol does not support connected, InvalidParameter
# If @protocol is invalid, InvalidParameter
# If any other error occurs, SetPasswdFailed
#
# Notes: If VNC is not enabled, SetPasswdFailed is returned.
#
# Since: 0.14.0
##
{ 'command': 'set_password',
'data': {'protocol': 'str', 'password': 'str', '*connected': 'str'} }
##
# @expire_password:
#
# Expire the password of a remote display server.
#
# @protocol: the name of the remote display protocol `vnc' or `spice'
#
# @time: when to expire the password.
# `now' to expire the password immediately
# `never' to cancel password expiration
# `+INT' where INT is the number of seconds from now (integer)
# `INT' where INT is the absolute time in seconds
#
# Returns: Nothing on success
# If @protocol is `spice' and Spice is not active, DeviceNotFound
# If an error occurs setting password expiration, SetPasswdFailed
# If @protocol is not `spice' or 'vnc', InvalidParameter
#
# Since: 0.14.0
#
# Notes: Time is relative to the server and currently there is no way to
# coordinate server time with client time. It is not recommended to
# use the absolute time version of the @time parameter unless you're
# sure you are on the same machine as the QEMU instance.
##
{ 'command': 'expire_password', 'data': {'protocol': 'str', 'time': 'str'} }
##
# @eject:
#
# Ejects a device from a removable drive.
#
# @device: The name of the device
#
# @force: @optional If true, eject regardless of whether the drive is locked.
# If not specified, the default value is false.
#
# Returns: Nothing on success
# If @device is not a valid block device, DeviceNotFound
# If @device is not removable and @force is false, DeviceNotRemovable
# If @force is false and @device is locked, DeviceLocked
#
# Notes: Ejecting a device will no media results in success
#
# Since: 0.14.0
##
{ 'command': 'eject', 'data': {'device': 'str', '*force': 'bool'} }
##
# @change-vnc-password:
#
# Change the VNC server password.
#
# @target: the new password to use with VNC authentication
#
# Since: 1.1
#
# Notes: An empty password in this command will set the password to the empty
# string. Existing clients are unaffected by executing this command.
##
{ 'command': 'change-vnc-password', 'data': {'password': 'str'} }
##
# @change:
#
# This command is multiple commands multiplexed together.
#
# @device: This is normally the name of a block device but it may also be 'vnc'.
# when it's 'vnc', then sub command depends on @target
#
# @target: If @device is a block device, then this is the new filename.
# If @device is 'vnc', then if the value 'password' selects the vnc
# change password command. Otherwise, this specifies a new server URI
# address to listen to for VNC connections.
#
# @arg: If @device is a block device, then this is an optional format to open
# the device with.
# If @device is 'vnc' and @target is 'password', this is the new VNC
# password to set. If this argument is an empty string, then no future
# logins will be allowed.
#
# Returns: Nothing on success.
# If @device is not a valid block device, DeviceNotFound
# If @format is not a valid block format, InvalidBlockFormat
# If the new block device is encrypted, DeviceEncrypted. Note that
# if this error is returned, the device has been opened successfully
# and an additional call to @block_passwd is required to set the
# device's password. The behavior of reads and writes to the block
# device between when these calls are executed is undefined.
#
# Notes: It is strongly recommended that this interface is not used especially
# for changing block devices.
#
# Since: 0.14.0
##
{ 'command': 'change',
'data': {'device': 'str', 'target': 'str', '*arg': 'str'} }
##
# @block_set_io_throttle:
#
# Change I/O throttle limits for a block drive.
#
# @device: The name of the device
#
# @bps: total throughput limit in bytes per second
#
# @bps_rd: read throughput limit in bytes per second
#
# @bps_wr: write throughput limit in bytes per second
#
# @iops: total I/O operations per second
#
# @ops_rd: read I/O operations per second
#
# @iops_wr: write I/O operations per second
#
# Returns: Nothing on success
# If @device is not a valid block device, DeviceNotFound
# If the argument combination is invalid, InvalidParameterCombination
#
# Since: 1.1
##
{ 'command': 'block_set_io_throttle',
'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int' } }

View File

@ -40,10 +40,13 @@ static const QType qerror_type = {
* "running out of foo: %(foo)%%" * "running out of foo: %(foo)%%"
* *
* Please keep the entries in alphabetical order. * Please keep the entries in alphabetical order.
* Use "sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c | sort -c" * Use scripts/check-qerror.sh to check.
* to check.
*/ */
static const QErrorStringTable qerror_table[] = { static const QErrorStringTable qerror_table[] = {
{
.error_fmt = QERR_ADD_CLIENT_FAILED,
.desc = "Could not add client",
},
{ {
.error_fmt = QERR_BAD_BUS_FOR_DEVICE, .error_fmt = QERR_BAD_BUS_FOR_DEVICE,
.desc = "Device '%(device)' can't go on a %(bad_bus_type) bus", .desc = "Device '%(device)' can't go on a %(bad_bus_type) bus",
@ -52,26 +55,34 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
.desc = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'", .desc = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
}, },
{
.error_fmt = QERR_BUS_NOT_FOUND,
.desc = "Bus '%(bus)' not found",
},
{ {
.error_fmt = QERR_BUS_NO_HOTPLUG, .error_fmt = QERR_BUS_NO_HOTPLUG,
.desc = "Bus '%(bus)' does not support hotplugging", .desc = "Bus '%(bus)' does not support hotplugging",
}, },
{ {
.error_fmt = QERR_COMMAND_NOT_FOUND, .error_fmt = QERR_BUS_NOT_FOUND,
.desc = "The command %(name) has not been found", .desc = "Bus '%(bus)' not found",
}, },
{ {
.error_fmt = QERR_COMMAND_DISABLED, .error_fmt = QERR_COMMAND_DISABLED,
.desc = "The command %(name) has been disabled for this instance", .desc = "The command %(name) has been disabled for this instance",
}, },
{
.error_fmt = QERR_COMMAND_NOT_FOUND,
.desc = "The command %(name) has not been found",
},
{ {
.error_fmt = QERR_DEVICE_ENCRYPTED, .error_fmt = QERR_DEVICE_ENCRYPTED,
.desc = "Device '%(device)' is encrypted", .desc = "Device '%(device)' is encrypted",
}, },
{
.error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
.desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
},
{
.error_fmt = QERR_DEVICE_HAS_NO_MEDIUM,
.desc = "Device '%(device)' has no medium",
},
{ {
.error_fmt = QERR_DEVICE_INIT_FAILED, .error_fmt = QERR_DEVICE_INIT_FAILED,
.desc = "Device '%(device)' could not be initialized", .desc = "Device '%(device)' could not be initialized",
@ -81,8 +92,8 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Device '%(device)' is in use", .desc = "Device '%(device)' is in use",
}, },
{ {
.error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, .error_fmt = QERR_DEVICE_IS_READ_ONLY,
.desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'", .desc = "Device '%(device)' is read only",
}, },
{ {
.error_fmt = QERR_DEVICE_LOCKED, .error_fmt = QERR_DEVICE_LOCKED,
@ -92,6 +103,14 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_DEVICE_MULTIPLE_BUSSES, .error_fmt = QERR_DEVICE_MULTIPLE_BUSSES,
.desc = "Device '%(device)' has multiple child busses", .desc = "Device '%(device)' has multiple child busses",
}, },
{
.error_fmt = QERR_DEVICE_NO_BUS,
.desc = "Device '%(device)' has no child bus",
},
{
.error_fmt = QERR_DEVICE_NO_HOTPLUG,
.desc = "Device '%(device)' does not support hotplugging",
},
{ {
.error_fmt = QERR_DEVICE_NOT_ACTIVE, .error_fmt = QERR_DEVICE_NOT_ACTIVE,
.desc = "Device '%(device)' has not been activated", .desc = "Device '%(device)' has not been activated",
@ -108,14 +127,6 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_DEVICE_NOT_REMOVABLE, .error_fmt = QERR_DEVICE_NOT_REMOVABLE,
.desc = "Device '%(device)' is not removable", .desc = "Device '%(device)' is not removable",
}, },
{
.error_fmt = QERR_DEVICE_NO_BUS,
.desc = "Device '%(device)' has no child bus",
},
{
.error_fmt = QERR_DEVICE_NO_HOTPLUG,
.desc = "Device '%(device)' does not support hotplugging",
},
{ {
.error_fmt = QERR_DUPLICATE_ID, .error_fmt = QERR_DUPLICATE_ID,
.desc = "Duplicate ID '%(id)' for %(object)", .desc = "Duplicate ID '%(id)' for %(object)",
@ -140,6 +151,10 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_INVALID_PARAMETER, .error_fmt = QERR_INVALID_PARAMETER,
.desc = "Invalid parameter '%(name)'", .desc = "Invalid parameter '%(name)'",
}, },
{
.error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
.desc = "Invalid parameter combination",
},
{ {
.error_fmt = QERR_INVALID_PARAMETER_TYPE, .error_fmt = QERR_INVALID_PARAMETER_TYPE,
.desc = "Invalid parameter type, expected: %(expected)", .desc = "Invalid parameter type, expected: %(expected)",
@ -156,15 +171,15 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_IO_ERROR, .error_fmt = QERR_IO_ERROR,
.desc = "An IO error has occurred", .desc = "An IO error has occurred",
}, },
{
.error_fmt = QERR_JSON_PARSING,
.desc = "Invalid JSON syntax",
},
{ {
.error_fmt = QERR_JSON_PARSE_ERROR, .error_fmt = QERR_JSON_PARSE_ERROR,
.desc = "JSON parse error, %(message)", .desc = "JSON parse error, %(message)",
}, },
{
.error_fmt = QERR_JSON_PARSING,
.desc = "Invalid JSON syntax",
},
{ {
.error_fmt = QERR_KVM_MISSING_CAP, .error_fmt = QERR_KVM_MISSING_CAP,
.desc = "Using KVM without %(capability), %(feature) unavailable", .desc = "Using KVM without %(capability), %(feature) unavailable",
@ -210,6 +225,14 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Property '%(device).%(property)' doesn't take " .desc = "Property '%(device).%(property)' doesn't take "
"value %(value) (minimum: %(min), maximum: %(max)'", "value %(value) (minimum: %(min), maximum: %(max)'",
}, },
{
.error_fmt = QERR_QGA_COMMAND_FAILED,
.desc = "Guest agent command failed, error was '%(message)'",
},
{
.error_fmt = QERR_QGA_LOGGING_FAILED,
.desc = "Guest agent failed to log non-optional log statement",
},
{ {
.error_fmt = QERR_QMP_BAD_INPUT_OBJECT, .error_fmt = QERR_QMP_BAD_INPUT_OBJECT,
.desc = "Expected '%(expected)' in QMP input", .desc = "Expected '%(expected)' in QMP input",
@ -230,10 +253,6 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_SET_PASSWD_FAILED, .error_fmt = QERR_SET_PASSWD_FAILED,
.desc = "Could not set password", .desc = "Could not set password",
}, },
{
.error_fmt = QERR_ADD_CLIENT_FAILED,
.desc = "Could not add client",
},
{ {
.error_fmt = QERR_TOO_MANY_FILES, .error_fmt = QERR_TOO_MANY_FILES,
.desc = "Too many open files", .desc = "Too many open files",
@ -242,15 +261,15 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_UNDEFINED_ERROR, .error_fmt = QERR_UNDEFINED_ERROR,
.desc = "An undefined error has occurred", .desc = "An undefined error has occurred",
}, },
{
.error_fmt = QERR_UNSUPPORTED,
.desc = "this feature or command is not currently supported",
},
{ {
.error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, .error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
.desc = "'%(device)' uses a %(format) feature which is not " .desc = "'%(device)' uses a %(format) feature which is not "
"supported by this qemu version: %(feature)", "supported by this qemu version: %(feature)",
}, },
{
.error_fmt = QERR_UNSUPPORTED,
.desc = "this feature or command is not currently supported",
},
{ {
.error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION, .error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
.desc = "Migration is disabled when VirtFS export path '%(path)' " .desc = "Migration is disabled when VirtFS export path '%(path)' "
@ -260,18 +279,6 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_VNC_SERVER_FAILED, .error_fmt = QERR_VNC_SERVER_FAILED,
.desc = "Could not start VNC server on %(target)", .desc = "Could not start VNC server on %(target)",
}, },
{
.error_fmt = QERR_QGA_LOGGING_FAILED,
.desc = "Guest agent failed to log non-optional log statement",
},
{
.error_fmt = QERR_QGA_COMMAND_FAILED,
.desc = "Guest agent command failed, error was '%(message)'",
},
{
.error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
.desc = "Invalid parameter combination",
},
{} {}
}; };

View File

@ -49,28 +49,40 @@ QError *qobject_to_qerror(const QObject *obj);
/* /*
* QError class list * QError class list
* Please keep the definitions in alphabetical order. * Please keep the definitions in alphabetical order.
* Use "grep '^#define QERR_' qerror.h | sort -c" to check. * Use scripts/check-qerror.sh to check.
*/ */
#define QERR_ADD_CLIENT_FAILED \
"{ 'class': 'AddClientFailed', 'data': {} }"
#define QERR_BAD_BUS_FOR_DEVICE \ #define QERR_BAD_BUS_FOR_DEVICE \
"{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }" "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
#define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \ #define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
"{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }" "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
#define QERR_BUS_NOT_FOUND \ #define QERR_BUFFER_OVERRUN \
"{ 'class': 'BusNotFound', 'data': { 'bus': %s } }" "{ 'class': 'BufferOverrun', 'data': {} }"
#define QERR_BUS_NO_HOTPLUG \ #define QERR_BUS_NO_HOTPLUG \
"{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }" "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
#define QERR_COMMAND_NOT_FOUND \ #define QERR_BUS_NOT_FOUND \
"{ 'class': 'CommandNotFound', 'data': { 'name': %s } }" "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
#define QERR_COMMAND_DISABLED \ #define QERR_COMMAND_DISABLED \
"{ 'class': 'CommandDisabled', 'data': { 'name': %s } }" "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
#define QERR_COMMAND_NOT_FOUND \
"{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
#define QERR_DEVICE_ENCRYPTED \ #define QERR_DEVICE_ENCRYPTED \
"{ 'class': 'DeviceEncrypted', 'data': { 'device': %s } }" "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
"{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
#define QERR_DEVICE_HAS_NO_MEDIUM \
"{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }"
#define QERR_DEVICE_INIT_FAILED \ #define QERR_DEVICE_INIT_FAILED \
"{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }" "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
@ -78,8 +90,8 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_DEVICE_IN_USE \ #define QERR_DEVICE_IN_USE \
"{ 'class': 'DeviceInUse', 'data': { 'device': %s } }" "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \ #define QERR_DEVICE_IS_READ_ONLY \
"{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }" "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
#define QERR_DEVICE_LOCKED \ #define QERR_DEVICE_LOCKED \
"{ 'class': 'DeviceLocked', 'data': { 'device': %s } }" "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
@ -87,6 +99,12 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_DEVICE_MULTIPLE_BUSSES \ #define QERR_DEVICE_MULTIPLE_BUSSES \
"{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }" "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
#define QERR_DEVICE_NO_BUS \
"{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
#define QERR_DEVICE_NO_HOTPLUG \
"{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
#define QERR_DEVICE_NOT_ACTIVE \ #define QERR_DEVICE_NOT_ACTIVE \
"{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }" "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
@ -99,12 +117,6 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_DEVICE_NOT_REMOVABLE \ #define QERR_DEVICE_NOT_REMOVABLE \
"{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }" "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
#define QERR_DEVICE_NO_BUS \
"{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
#define QERR_DEVICE_NO_HOTPLUG \
"{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
#define QERR_DUPLICATE_ID \ #define QERR_DUPLICATE_ID \
"{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }" "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
@ -114,12 +126,18 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_FD_NOT_SUPPLIED \ #define QERR_FD_NOT_SUPPLIED \
"{ 'class': 'FdNotSupplied', 'data': {} }" "{ 'class': 'FdNotSupplied', 'data': {} }"
#define QERR_FEATURE_DISABLED \
"{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
#define QERR_INVALID_BLOCK_FORMAT \ #define QERR_INVALID_BLOCK_FORMAT \
"{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }" "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
#define QERR_INVALID_PARAMETER \ #define QERR_INVALID_PARAMETER \
"{ 'class': 'InvalidParameter', 'data': { 'name': %s } }" "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
#define QERR_INVALID_PARAMETER_COMBINATION \
"{ 'class': 'InvalidParameterCombination', 'data': {} }"
#define QERR_INVALID_PARAMETER_TYPE \ #define QERR_INVALID_PARAMETER_TYPE \
"{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }" "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
@ -132,14 +150,11 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_IO_ERROR \ #define QERR_IO_ERROR \
"{ 'class': 'IOError', 'data': {} }" "{ 'class': 'IOError', 'data': {} }"
#define QERR_JSON_PARSING \
"{ 'class': 'JSONParsing', 'data': {} }"
#define QERR_JSON_PARSE_ERROR \ #define QERR_JSON_PARSE_ERROR \
"{ 'class': 'JSONParseError', 'data': { 'message': %s } }" "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
#define QERR_BUFFER_OVERRUN \ #define QERR_JSON_PARSING \
"{ 'class': 'BufferOverrun', 'data': {} }" "{ 'class': 'JSONParsing', 'data': {} }"
#define QERR_KVM_MISSING_CAP \ #define QERR_KVM_MISSING_CAP \
"{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }" "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
@ -174,6 +189,12 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_PROPERTY_VALUE_OUT_OF_RANGE \ #define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
"{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }" "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
#define QERR_QGA_COMMAND_FAILED \
"{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
#define QERR_QGA_LOGGING_FAILED \
"{ 'class': 'QgaLoggingFailed', 'data': {} }"
#define QERR_QMP_BAD_INPUT_OBJECT \ #define QERR_QMP_BAD_INPUT_OBJECT \
"{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }" "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
@ -189,37 +210,22 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_SET_PASSWD_FAILED \ #define QERR_SET_PASSWD_FAILED \
"{ 'class': 'SetPasswdFailed', 'data': {} }" "{ 'class': 'SetPasswdFailed', 'data': {} }"
#define QERR_ADD_CLIENT_FAILED \
"{ 'class': 'AddClientFailed', 'data': {} }"
#define QERR_TOO_MANY_FILES \ #define QERR_TOO_MANY_FILES \
"{ 'class': 'TooManyFiles', 'data': {} }" "{ 'class': 'TooManyFiles', 'data': {} }"
#define QERR_UNDEFINED_ERROR \ #define QERR_UNDEFINED_ERROR \
"{ 'class': 'UndefinedError', 'data': {} }" "{ 'class': 'UndefinedError', 'data': {} }"
#define QERR_UNSUPPORTED \
"{ 'class': 'Unsupported', 'data': {} }"
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \ #define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }" "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
#define QERR_UNSUPPORTED \
"{ 'class': 'Unsupported', 'data': {} }"
#define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \ #define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
"{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }" "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
#define QERR_VNC_SERVER_FAILED \ #define QERR_VNC_SERVER_FAILED \
"{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }" "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
#define QERR_FEATURE_DISABLED \
"{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
#define QERR_QGA_LOGGING_FAILED \
"{ 'class': 'QgaLoggingFailed', 'data': {} }"
#define QERR_QGA_COMMAND_FAILED \
"{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
#define QERR_INVALID_PARAMETER_COMBINATION \
"{ 'class': 'InvalidParameterCombination', 'data': {} }"
#endif /* QERROR_H */ #endif /* QERROR_H */

View File

@ -84,10 +84,7 @@ EQMP
{ {
.name = "eject", .name = "eject",
.args_type = "force:-f,device:B", .args_type = "force:-f,device:B",
.params = "[-f] device", .mhandler.cmd_new = qmp_marshal_input_eject,
.help = "eject a removable medium (use -f to force it)",
.user_print = monitor_user_noop,
.mhandler.cmd_new = do_eject,
}, },
SQMP SQMP
@ -113,10 +110,7 @@ EQMP
{ {
.name = "change", .name = "change",
.args_type = "device:B,target:F,arg:s?", .args_type = "device:B,target:F,arg:s?",
.params = "device filename [format]", .mhandler.cmd_new = qmp_marshal_input_change,
.help = "change a removable medium, optional format",
.user_print = monitor_user_noop,
.mhandler.cmd_new = do_change,
}, },
SQMP SQMP
@ -813,10 +807,7 @@ EQMP
{ {
.name = "block_set_io_throttle", .name = "block_set_io_throttle",
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l", .args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
.params = "device bps bps_rd bps_wr iops iops_rd iops_wr", .mhandler.cmd_new = qmp_marshal_input_block_set_io_throttle,
.help = "change I/O throttle limits for a block drive",
.user_print = monitor_user_noop,
.mhandler.cmd_new = do_block_set_io_throttle,
}, },
SQMP SQMP
@ -851,10 +842,7 @@ EQMP
{ {
.name = "set_password", .name = "set_password",
.args_type = "protocol:s,password:s,connected:s?", .args_type = "protocol:s,password:s,connected:s?",
.params = "protocol password action-if-connected", .mhandler.cmd_new = qmp_marshal_input_set_password,
.help = "set spice/vnc password",
.user_print = monitor_user_noop,
.mhandler.cmd_new = set_password,
}, },
SQMP SQMP
@ -880,10 +868,7 @@ EQMP
{ {
.name = "expire_password", .name = "expire_password",
.args_type = "protocol:s,time:s", .args_type = "protocol:s,time:s",
.params = "protocol time", .mhandler.cmd_new = qmp_marshal_input_expire_password,
.help = "set spice/vnc password expire-time",
.user_print = monitor_user_noop,
.mhandler.cmd_new = expire_password,
}, },
SQMP SQMP
@ -2027,3 +2012,9 @@ EQMP
.args_type = "path:s,property:s", .args_type = "path:s,property:s",
.mhandler.cmd_new = qmp_qom_get, .mhandler.cmd_new = qmp_qom_get,
}, },
{
.name = "change-vnc-password",
.args_type = "password:s",
.mhandler.cmd_new = qmp_marshal_input_change_vnc_password,
},

148
qmp.c
View File

@ -16,11 +16,14 @@
#include "qemu-common.h" #include "qemu-common.h"
#include "sysemu.h" #include "sysemu.h"
#include "qmp-commands.h" #include "qmp-commands.h"
#include "ui/qemu-spice.h"
#include "ui/vnc.h"
#include "kvm.h" #include "kvm.h"
#include "arch_init.h" #include "arch_init.h"
#include "hw/qdev.h" #include "hw/qdev.h"
#include "qapi/qmp-input-visitor.h" #include "qapi/qmp-input-visitor.h"
#include "qapi/qmp-output-visitor.h" #include "qapi/qmp-output-visitor.h"
#include "blockdev.h"
NameInfo *qmp_query_name(Error **errp) NameInfo *qmp_query_name(Error **errp)
{ {
@ -133,7 +136,8 @@ static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
Error **err = opaque; Error **err = opaque;
if (!error_is_set(err) && bdrv_key_required(bs)) { if (!error_is_set(err) && bdrv_key_required(bs)) {
error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs)); error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
bdrv_get_encrypted_filename(bs));
} }
} }
@ -249,3 +253,145 @@ out:
return 0; return 0;
} }
void qmp_set_password(const char *protocol, const char *password,
bool has_connected, const char *connected, Error **errp)
{
int disconnect_if_connected = 0;
int fail_if_connected = 0;
int rc;
if (has_connected) {
if (strcmp(connected, "fail") == 0) {
fail_if_connected = 1;
} else if (strcmp(connected, "disconnect") == 0) {
disconnect_if_connected = 1;
} else if (strcmp(connected, "keep") == 0) {
/* nothing */
} else {
error_set(errp, QERR_INVALID_PARAMETER, "connected");
return;
}
}
if (strcmp(protocol, "spice") == 0) {
if (!using_spice) {
/* correct one? spice isn't a device ,,, */
error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
return;
}
rc = qemu_spice_set_passwd(password, fail_if_connected,
disconnect_if_connected);
if (rc != 0) {
error_set(errp, QERR_SET_PASSWD_FAILED);
}
return;
}
if (strcmp(protocol, "vnc") == 0) {
if (fail_if_connected || disconnect_if_connected) {
/* vnc supports "connected=keep" only */
error_set(errp, QERR_INVALID_PARAMETER, "connected");
return;
}
/* Note that setting an empty password will not disable login through
* this interface. */
rc = vnc_display_password(NULL, password);
if (rc < 0) {
error_set(errp, QERR_SET_PASSWD_FAILED);
}
return;
}
error_set(errp, QERR_INVALID_PARAMETER, "protocol");
}
void qmp_expire_password(const char *protocol, const char *whenstr,
Error **errp)
{
time_t when;
int rc;
if (strcmp(whenstr, "now") == 0) {
when = 0;
} else if (strcmp(whenstr, "never") == 0) {
when = TIME_MAX;
} else if (whenstr[0] == '+') {
when = time(NULL) + strtoull(whenstr+1, NULL, 10);
} else {
when = strtoull(whenstr, NULL, 10);
}
if (strcmp(protocol, "spice") == 0) {
if (!using_spice) {
/* correct one? spice isn't a device ,,, */
error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
return;
}
rc = qemu_spice_set_pw_expire(when);
if (rc != 0) {
error_set(errp, QERR_SET_PASSWD_FAILED);
}
return;
}
if (strcmp(protocol, "vnc") == 0) {
rc = vnc_display_pw_expire(NULL, when);
if (rc != 0) {
error_set(errp, QERR_SET_PASSWD_FAILED);
}
return;
}
error_set(errp, QERR_INVALID_PARAMETER, "protocol");
}
#ifdef CONFIG_VNC
void qmp_change_vnc_password(const char *password, Error **errp)
{
if (vnc_display_password(NULL, password) < 0) {
error_set(errp, QERR_SET_PASSWD_FAILED);
}
}
static void qmp_change_vnc_listen(const char *target, Error **err)
{
if (vnc_display_open(NULL, target) < 0) {
error_set(err, QERR_VNC_SERVER_FAILED, target);
}
}
static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
Error **errp)
{
if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) {
if (!has_arg) {
error_set(errp, QERR_MISSING_PARAMETER, "password");
} else {
qmp_change_vnc_password(arg, errp);
}
} else {
qmp_change_vnc_listen(target, errp);
}
}
#else
void qmp_change_vnc_password(const char *password, Error **errp)
{
error_set(errp, QERR_FEATURE_DISABLED, "vnc");
}
static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
Error **errp)
{
error_set(errp, QERR_FEATURE_DISABLED, "vnc");
}
#endif /* !CONFIG_VNC */
void qmp_change(const char *device, const char *target,
bool has_arg, const char *arg, Error **err)
{
if (strcmp(device, "vnc") == 0) {
qmp_change_vnc(target, has_arg, arg, err);
} else {
qmp_change_blockdev(device, target, has_arg, arg, err);
}
}

22
scripts/check-qerror.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
# This script verifies that qerror definitions and table entries are
# alphabetically ordered.
check_order() {
errmsg=$1
shift
# sort -C verifies order but does not print a message. sort -c does print a
# message. These options are both in POSIX.
if ! "$@" | sort -C; then
echo "$errmsg"
"$@" | sort -c
exit 1
fi
return 0
}
check_order 'Definitions in qerror.h must be in alphabetical order:' \
grep '^#define QERR_' qerror.h
check_order 'Entries in qerror.c:qerror_table must be in alphabetical order:' \
sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c

View File

@ -38,7 +38,8 @@ static void visitor_input_teardown(TestInputVisitorData *data,
/* This is provided instead of a test setup function so that the JSON /* This is provided instead of a test setup function so that the JSON
string used by the tests are kept in the test functions (and not string used by the tests are kept in the test functions (and not
int main()) */ int main()) */
static Visitor *visitor_input_test_init(TestInputVisitorData *data, static GCC_FMT_ATTR(2, 3)
Visitor *visitor_input_test_init(TestInputVisitorData *data,
const char *json_string, ...) const char *json_string, ...)
{ {
Visitor *v; Visitor *v;
@ -66,7 +67,7 @@ static void test_visitor_in_int(TestInputVisitorData *data,
Error *errp = NULL; Error *errp = NULL;
Visitor *v; Visitor *v;
v = visitor_input_test_init(data, "%d", value); v = visitor_input_test_init(data, "%" PRId64, value);
visit_type_int(v, &res, NULL, &errp); visit_type_int(v, &res, NULL, &errp);
g_assert(!error_is_set(&errp)); g_assert(!error_is_set(&errp));

View File

@ -2686,19 +2686,16 @@ int vnc_display_disable_login(DisplayState *ds)
int vnc_display_password(DisplayState *ds, const char *password) int vnc_display_password(DisplayState *ds, const char *password)
{ {
int ret = 0;
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
if (!vs) { if (!vs) {
ret = -EINVAL; return -EINVAL;
goto out;
} }
if (!password) { if (!password) {
/* This is not the intention of this interface but err on the side /* This is not the intention of this interface but err on the side
of being safe */ of being safe */
ret = vnc_display_disable_login(ds); return vnc_display_disable_login(ds);
goto out;
} }
if (vs->password) { if (vs->password) {
@ -2707,11 +2704,8 @@ int vnc_display_password(DisplayState *ds, const char *password)
} }
vs->password = g_strdup(password); vs->password = g_strdup(password);
vs->auth = VNC_AUTH_VNC; vs->auth = VNC_AUTH_VNC;
out:
if (ret != 0) { return 0;
qerror_report(QERR_SET_PASSWD_FAILED);
}
return ret;
} }
int vnc_display_pw_expire(DisplayState *ds, time_t expires) int vnc_display_pw_expire(DisplayState *ds, time_t expires)