aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2012-01-19 09:23:16 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2012-01-19 09:23:16 -0600
commitb48c0134de96f3deed15a0e115d58f3cff09f3c1 (patch)
tree2df65714d6e3282b5f6478264e2cc0c57ab7cfa2
parent5414b32542662976c364b58011c4841304569aff (diff)
parent939a1cc399adb92640d156097d528b6471c136ae (diff)
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()
-rw-r--r--blockdev.c155
-rw-r--r--blockdev.h8
-rw-r--r--console.h3
-rw-r--r--hmp-commands.hx15
-rw-r--r--hmp.c102
-rw-r--r--hmp.h5
-rw-r--r--monitor.c179
-rw-r--r--monitor.h5
-rw-r--r--qapi-schema.json163
-rw-r--r--qerror.c91
-rw-r--r--qerror.h80
-rw-r--r--qmp-commands.hx31
-rw-r--r--qmp.c148
-rwxr-xr-xscripts/check-qerror.sh22
-rw-r--r--test-qmp-input-visitor.c7
-rw-r--r--ui/vnc.c14
16 files changed, 657 insertions, 371 deletions
diff --git a/blockdev.c b/blockdev.c
index c832782d03..1f83c888e7 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -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)) {
- qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
+ return;
}
+
if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
bdrv_dev_eject_request(bs, force);
if (!force) {
- qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
- return -1;
+ error_set(errp, QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
+ return;
}
}
+
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;
- 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) {
- qerror_report(QERR_DEVICE_NOT_FOUND, filename);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
}
- return eject_device(mon, bs, force);
+
+ eject_device(bs, force, 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,
- const char *filename, const char *fmt)
+static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
+ 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;
BlockDriver *drv = NULL;
int bdrv_flags;
+ Error *err = NULL;
bs = bdrv_find(device);
if (!bs) {
- qerror_report(QERR_DEVICE_NOT_FOUND, device);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
}
- if (fmt) {
- drv = bdrv_find_whitelisted_format(fmt);
+
+ if (format) {
+ drv = bdrv_find_whitelisted_format(format);
if (!drv) {
- qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt);
- return -1;
+ error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
+ 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_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
- if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
- qerror_report(QERR_OPEN_FILE_FAILED, filename);
- return -1;
- }
- return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
+
+ qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp);
}
/* throttling disk I/O limits */
-int do_block_set_io_throttle(Monitor *mon,
- const QDict *qdict, QObject **ret_data)
+void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
+ int64_t bps_wr, int64_t iops, int64_t iops_rd,
+ int64_t iops_wr, Error **errp)
{
BlockIOLimit io_limits;
- const char *devname = qdict_get_str(qdict, "device");
BlockDriverState *bs;
- io_limits.bps[BLOCK_IO_LIMIT_TOTAL]
- = 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);
+ bs = bdrv_find(device);
if (!bs) {
- qerror_report(QERR_DEVICE_NOT_FOUND, devname);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
}
- if ((io_limits.bps[BLOCK_IO_LIMIT_TOTAL] == -1)
- || (io_limits.bps[BLOCK_IO_LIMIT_READ] == -1)
- || (io_limits.bps[BLOCK_IO_LIMIT_WRITE] == -1)
- || (io_limits.iops[BLOCK_IO_LIMIT_TOTAL] == -1)
- || (io_limits.iops[BLOCK_IO_LIMIT_READ] == -1)
- || (io_limits.iops[BLOCK_IO_LIMIT_WRITE] == -1)) {
- qerror_report(QERR_MISSING_PARAMETER,
- "bps/bps_rd/bps_wr/iops/iops_rd/iops_wr");
- return -1;
- }
+ io_limits.bps[BLOCK_IO_LIMIT_TOTAL] = bps;
+ io_limits.bps[BLOCK_IO_LIMIT_READ] = bps_rd;
+ io_limits.bps[BLOCK_IO_LIMIT_WRITE] = bps_wr;
+ io_limits.iops[BLOCK_IO_LIMIT_TOTAL]= iops;
+ io_limits.iops[BLOCK_IO_LIMIT_READ] = iops_rd;
+ io_limits.iops[BLOCK_IO_LIMIT_WRITE]= iops_wr;
if (!do_check_io_limits(&io_limits)) {
- qerror_report(QERR_INVALID_PARAMETER_COMBINATION);
- return -1;
+ error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
+ return;
}
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));
}
}
-
- return 0;
}
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;
}
-/*
- * 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)
{
BlockDriverState *bs;
@@ -857,12 +859,27 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
}
if (size < 0) {
- error_set(errp, QERR_UNDEFINED_ERROR);
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
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);
- return;
+ break;
}
}
diff --git a/blockdev.h b/blockdev.h
index f1b639660d..260e16b3c6 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -11,6 +11,7 @@
#define BLOCKDEV_H
#include "block.h"
+#include "error.h"
#include "qemu-queue.h"
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);
+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);
-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_block_set_io_throttle(Monitor *mon,
- const QDict *qdict, QObject **ret_data);
#endif
diff --git a/console.h b/console.h
index 9466886b59..6ba0d5ddf3 100644
--- a/console.h
+++ b/console.h
@@ -4,7 +4,6 @@
#include "qemu-char.h"
#include "qdict.h"
#include "notify.h"
-#include "qerror.h"
#include "monitor.h"
/* keyboard/mouse support */
@@ -384,12 +383,10 @@ int vnc_display_pw_expire(DisplayState *ds, time_t expires);
#else
static inline int vnc_display_password(DisplayState *ds, const char *password)
{
- qerror_report(QERR_FEATURE_DISABLED, "vnc");
return -ENODEV;
}
static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
{
- qerror_report(QERR_FEATURE_DISABLED, "vnc");
return -ENODEV;
};
#endif
diff --git a/hmp-commands.hx b/hmp-commands.hx
index a586498495..e6506fc9d3 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -75,8 +75,7 @@ ETEXI
.args_type = "force:-f,device:B",
.params = "[-f] device",
.help = "eject a removable medium (use -f to force it)",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_eject,
+ .mhandler.cmd = hmp_eject,
},
STEXI
@@ -108,8 +107,7 @@ ETEXI
.args_type = "device:B,target:F,arg:s?",
.params = "device filename [format]",
.help = "change a removable medium, optional format",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_change,
+ .mhandler.cmd = hmp_change,
},
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",
.params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
.help = "change I/O throttle limits for a block drive",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_block_set_io_throttle,
+ .mhandler.cmd = hmp_block_set_io_throttle,
},
STEXI
@@ -1219,8 +1216,7 @@ ETEXI
.args_type = "protocol:s,password:s,connected:s?",
.params = "protocol password action-if-connected",
.help = "set spice/vnc password",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = set_password,
+ .mhandler.cmd = hmp_set_password,
},
STEXI
@@ -1240,8 +1236,7 @@ ETEXI
.args_type = "protocol:s,time:s",
.params = "protocol time",
.help = "set spice/vnc password expire-time",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = expire_password,
+ .mhandler.cmd = hmp_expire_password,
},
STEXI
diff --git a/hmp.c b/hmp.c
index 8a777804de..4664dbe8e4 100644
--- a/hmp.c
+++ b/hmp.c
@@ -681,3 +681,105 @@ void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
int64_t value = qdict_get_int(qdict, "value");
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);
+}
diff --git a/hmp.h b/hmp.h
index 093242d626..aab0b1f508 100644
--- a/hmp.h
+++ b/hmp.h
@@ -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_set_downtime(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
diff --git a/monitor.c b/monitor.c
index 733440115f..187083c450 100644
--- a/monitor.c
+++ b/monitor.c
@@ -227,7 +227,7 @@ int monitor_cur_is_qmp(void)
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)
return;
@@ -237,8 +237,8 @@ static void monitor_read_command(Monitor *mon, int show_prompt)
readline_show_prompt(mon->rs);
}
-static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
- void *opaque)
+int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
+ void *opaque)
{
if (monitor_ctrl_mode(mon)) {
qerror_report(QERR_MISSING_PARAMETER, "password");
@@ -810,171 +810,6 @@ static void do_trace_print_events(Monitor *mon)
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)
{
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);
}
+ReadLineState *monitor_get_rs(Monitor *mon)
+{
+ return mon->rs;
+}
+
int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
BlockDriverCompletionFunc *completion_cb,
void *opaque)
@@ -4768,7 +4608,8 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
}
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;
}
diff --git a/monitor.h b/monitor.h
index cfa2f679f4..887c472a92 100644
--- a/monitor.h
+++ b/monitor.h
@@ -6,6 +6,7 @@
#include "qerror.h"
#include "qdict.h"
#include "block.h"
+#include "readline.h"
extern Monitor *cur_mon;
extern Monitor *default_mon;
@@ -66,6 +67,10 @@ int monitor_get_cpu_index(void);
typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
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);
diff --git a/qapi-schema.json b/qapi-schema.json
index 44cf764ec3..735eb352b5 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1064,8 +1064,11 @@
#
# Returns: nothing on success
# If @device is not a valid block device, DeviceNotFound
-#
-# Notes: This command returns UndefinedError in a number of error conditions.
+# If @size is negative, InvalidParameterValue
+# 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
##
@@ -1275,3 +1278,159 @@
{ 'command': 'qom-set',
'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' },
'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' } }
diff --git a/qerror.c b/qerror.c
index 9a75d06301..3d95383940 100644
--- a/qerror.c
+++ b/qerror.c
@@ -40,11 +40,14 @@ static const QType qerror_type = {
* "running out of foo: %(foo)%%"
*
* Please keep the entries in alphabetical order.
- * Use "sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c | sort -c"
- * to check.
+ * Use scripts/check-qerror.sh to check.
*/
static const QErrorStringTable qerror_table[] = {
{
+ .error_fmt = QERR_ADD_CLIENT_FAILED,
+ .desc = "Could not add client",
+ },
+ {
.error_fmt = QERR_BAD_BUS_FOR_DEVICE,
.desc = "Device '%(device)' can't go on a %(bad_bus_type) bus",
},
@@ -53,26 +56,34 @@ static const QErrorStringTable qerror_table[] = {
.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,
.desc = "Bus '%(bus)' does not support hotplugging",
},
{
- .error_fmt = QERR_COMMAND_NOT_FOUND,
- .desc = "The command %(name) has not been found",
+ .error_fmt = QERR_BUS_NOT_FOUND,
+ .desc = "Bus '%(bus)' not found",
},
{
.error_fmt = QERR_COMMAND_DISABLED,
.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,
.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,
.desc = "Device '%(device)' could not be initialized",
},
@@ -81,8 +92,8 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Device '%(device)' is in use",
},
{
- .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
- .desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
+ .error_fmt = QERR_DEVICE_IS_READ_ONLY,
+ .desc = "Device '%(device)' is read only",
},
{
.error_fmt = QERR_DEVICE_LOCKED,
@@ -93,6 +104,14 @@ static const QErrorStringTable qerror_table[] = {
.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,
.desc = "Device '%(device)' has not been activated",
},
@@ -109,14 +128,6 @@ static const QErrorStringTable qerror_table[] = {
.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,
.desc = "Duplicate ID '%(id)' for %(object)",
},
@@ -141,6 +152,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Invalid parameter '%(name)'",
},
{
+ .error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
+ .desc = "Invalid parameter combination",
+ },
+ {
.error_fmt = QERR_INVALID_PARAMETER_TYPE,
.desc = "Invalid parameter type, expected: %(expected)",
},
@@ -157,15 +172,15 @@ static const QErrorStringTable qerror_table[] = {
.desc = "An IO error has occurred",
},
{
- .error_fmt = QERR_JSON_PARSING,
- .desc = "Invalid JSON syntax",
- },
- {
.error_fmt = QERR_JSON_PARSE_ERROR,
.desc = "JSON parse error, %(message)",
},
{
+ .error_fmt = QERR_JSON_PARSING,
+ .desc = "Invalid JSON syntax",
+ },
+ {
.error_fmt = QERR_KVM_MISSING_CAP,
.desc = "Using KVM without %(capability), %(feature) unavailable",
},
@@ -211,6 +226,14 @@ static const QErrorStringTable qerror_table[] = {
"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,
.desc = "Expected '%(expected)' in QMP input",
},
@@ -231,10 +254,6 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Could not set password",
},
{
- .error_fmt = QERR_ADD_CLIENT_FAILED,
- .desc = "Could not add client",
- },
- {
.error_fmt = QERR_TOO_MANY_FILES,
.desc = "Too many open files",
},
@@ -243,15 +262,15 @@ static const QErrorStringTable qerror_table[] = {
.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,
.desc = "'%(device)' uses a %(format) feature which is not "
"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,
.desc = "Migration is disabled when VirtFS export path '%(path)' "
"is mounted in the guest using mount_tag '%(tag)'",
@@ -260,18 +279,6 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_VNC_SERVER_FAILED,
.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",
- },
{}
};
diff --git a/qerror.h b/qerror.h
index efda232db3..89160dd78e 100644
--- a/qerror.h
+++ b/qerror.h
@@ -49,28 +49,40 @@ QError *qobject_to_qerror(const QObject *obj);
/*
* QError class list
* 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 \
"{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
#define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
"{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
-#define QERR_BUS_NOT_FOUND \
- "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
+#define QERR_BUFFER_OVERRUN \
+ "{ 'class': 'BufferOverrun', 'data': {} }"
#define QERR_BUS_NO_HOTPLUG \
"{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
-#define QERR_COMMAND_NOT_FOUND \
- "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+#define QERR_BUS_NOT_FOUND \
+ "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
#define QERR_COMMAND_DISABLED \
"{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
+#define QERR_COMMAND_NOT_FOUND \
+ "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+
#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 \
"{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
@@ -78,8 +90,8 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_DEVICE_IN_USE \
"{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
-#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
- "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+#define QERR_DEVICE_IS_READ_ONLY \
+ "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
#define QERR_DEVICE_LOCKED \
"{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
@@ -87,6 +99,12 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_DEVICE_MULTIPLE_BUSSES \
"{ '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 \
"{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
@@ -99,12 +117,6 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_DEVICE_NOT_REMOVABLE \
"{ '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 \
"{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
@@ -114,12 +126,18 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_FD_NOT_SUPPLIED \
"{ 'class': 'FdNotSupplied', 'data': {} }"
+#define QERR_FEATURE_DISABLED \
+ "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
+
#define QERR_INVALID_BLOCK_FORMAT \
"{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
#define QERR_INVALID_PARAMETER \
"{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
+#define QERR_INVALID_PARAMETER_COMBINATION \
+ "{ 'class': 'InvalidParameterCombination', 'data': {} }"
+
#define QERR_INVALID_PARAMETER_TYPE \
"{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
@@ -132,14 +150,11 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_IO_ERROR \
"{ 'class': 'IOError', 'data': {} }"
-#define QERR_JSON_PARSING \
- "{ 'class': 'JSONParsing', 'data': {} }"
-
#define QERR_JSON_PARSE_ERROR \
"{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
-#define QERR_BUFFER_OVERRUN \
- "{ 'class': 'BufferOverrun', 'data': {} }"
+#define QERR_JSON_PARSING \
+ "{ 'class': 'JSONParsing', 'data': {} }"
#define QERR_KVM_MISSING_CAP \
"{ '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 \
"{ '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 \
"{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
@@ -189,37 +210,22 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_SET_PASSWD_FAILED \
"{ 'class': 'SetPasswdFailed', 'data': {} }"
-#define QERR_ADD_CLIENT_FAILED \
- "{ 'class': 'AddClientFailed', 'data': {} }"
-
#define QERR_TOO_MANY_FILES \
"{ 'class': 'TooManyFiles', 'data': {} }"
#define QERR_UNDEFINED_ERROR \
"{ 'class': 'UndefinedError', 'data': {} }"
-#define QERR_UNSUPPORTED \
- "{ 'class': 'Unsupported', 'data': {} }"
-
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
+#define QERR_UNSUPPORTED \
+ "{ 'class': 'Unsupported', 'data': {} }"
+
#define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
"{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
#define QERR_VNC_SERVER_FAILED \
"{ '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 */
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 7e3f4b9a59..799e655988 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -84,10 +84,7 @@ EQMP
{
.name = "eject",
.args_type = "force:-f,device:B",
- .params = "[-f] device",
- .help = "eject a removable medium (use -f to force it)",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_eject,
+ .mhandler.cmd_new = qmp_marshal_input_eject,
},
SQMP
@@ -113,10 +110,7 @@ EQMP
{
.name = "change",
.args_type = "device:B,target:F,arg:s?",
- .params = "device filename [format]",
- .help = "change a removable medium, optional format",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_change,
+ .mhandler.cmd_new = qmp_marshal_input_change,
},
SQMP
@@ -813,10 +807,7 @@ EQMP
{
.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",
- .params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
- .help = "change I/O throttle limits for a block drive",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_block_set_io_throttle,
+ .mhandler.cmd_new = qmp_marshal_input_block_set_io_throttle,
},
SQMP
@@ -851,10 +842,7 @@ EQMP
{
.name = "set_password",
.args_type = "protocol:s,password:s,connected:s?",
- .params = "protocol password action-if-connected",
- .help = "set spice/vnc password",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = set_password,
+ .mhandler.cmd_new = qmp_marshal_input_set_password,
},
SQMP
@@ -880,10 +868,7 @@ EQMP
{
.name = "expire_password",
.args_type = "protocol:s,time:s",
- .params = "protocol time",
- .help = "set spice/vnc password expire-time",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = expire_password,
+ .mhandler.cmd_new = qmp_marshal_input_expire_password,
},
SQMP
@@ -2027,3 +2012,9 @@ EQMP
.args_type = "path:s,property:s",
.mhandler.cmd_new = qmp_qom_get,
},
+
+ {
+ .name = "change-vnc-password",
+ .args_type = "password:s",
+ .mhandler.cmd_new = qmp_marshal_input_change_vnc_password,
+ },
diff --git a/qmp.c b/qmp.c
index c74dde6c90..1222b6c9c4 100644
--- a/qmp.c
+++ b/qmp.c
@@ -16,11 +16,14 @@
#include "qemu-common.h"
#include "sysemu.h"
#include "qmp-commands.h"
+#include "ui/qemu-spice.h"
+#include "ui/vnc.h"
#include "kvm.h"
#include "arch_init.h"
#include "hw/qdev.h"
#include "qapi/qmp-input-visitor.h"
#include "qapi/qmp-output-visitor.h"
+#include "blockdev.h"
NameInfo *qmp_query_name(Error **errp)
{
@@ -133,7 +136,8 @@ static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
Error **err = opaque;
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;
}
+
+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);
+ }
+}
diff --git a/scripts/check-qerror.sh b/scripts/check-qerror.sh
new file mode 100755
index 0000000000..af7fbd5249
--- /dev/null
+++ b/scripts/check-qerror.sh
@@ -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
diff --git a/test-qmp-input-visitor.c b/test-qmp-input-visitor.c
index 1f3ab031f7..926db5cb91 100644
--- a/test-qmp-input-visitor.c
+++ b/test-qmp-input-visitor.c
@@ -38,8 +38,9 @@ static void visitor_input_teardown(TestInputVisitorData *data,
/* 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
int main()) */
-static Visitor *visitor_input_test_init(TestInputVisitorData *data,
- const char *json_string, ...)
+static GCC_FMT_ATTR(2, 3)
+Visitor *visitor_input_test_init(TestInputVisitorData *data,
+ const char *json_string, ...)
{
Visitor *v;
va_list ap;
@@ -66,7 +67,7 @@ static void test_visitor_in_int(TestInputVisitorData *data,
Error *errp = NULL;
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);
g_assert(!error_is_set(&errp));
diff --git a/ui/vnc.c b/ui/vnc.c
index 1869a7adea..16b79ec423 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2686,19 +2686,16 @@ int vnc_display_disable_login(DisplayState *ds)
int vnc_display_password(DisplayState *ds, const char *password)
{
- int ret = 0;
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
if (!vs) {
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (!password) {
/* This is not the intention of this interface but err on the side
of being safe */
- ret = vnc_display_disable_login(ds);
- goto out;
+ return vnc_display_disable_login(ds);
}
if (vs->password) {
@@ -2707,11 +2704,8 @@ int vnc_display_password(DisplayState *ds, const char *password)
}
vs->password = g_strdup(password);
vs->auth = VNC_AUTH_VNC;
-out:
- if (ret != 0) {
- qerror_report(QERR_SET_PASSWD_FAILED);
- }
- return ret;
+
+ return 0;
}
int vnc_display_pw_expire(DisplayState *ds, time_t expires)