From a6aa9d3e2681199d159963e46524625d90669619 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 7 Dec 2011 10:19:10 -0200 Subject: [PATCH 01/14] vnc: Simplify vnc_display_password() Drop the qerror_report() call from it and let its callers set the error themselves. This also allows for dropping the 'ret' variable. Signed-off-by: Luiz Capitulino --- console.h | 1 - monitor.c | 7 ++++++- ui/vnc.c | 14 ++++---------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/console.h b/console.h index 9466886b59..be3b7c8b4f 100644 --- a/console.h +++ b/console.h @@ -384,7 +384,6 @@ 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) diff --git a/monitor.c b/monitor.c index 733440115f..759c1335c3 100644 --- a/monitor.c +++ b/monitor.c @@ -929,7 +929,12 @@ static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data) } /* Note that setting an empty password will not disable login through * this interface. */ - return vnc_display_password(NULL, password); + rc = vnc_display_password(NULL, password); + if (rc < 0) { + qerror_report(QERR_SET_PASSWD_FAILED); + return -1; + } + return 0; } qerror_report(QERR_INVALID_PARAMETER, "protocol"); 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) From fbf796fd6f855313d2c02b7d8e1a0c4241b1e0b6 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 7 Dec 2011 11:17:51 -0200 Subject: [PATCH 02/14] qapi: Convert set_password Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- hmp-commands.hx | 3 +-- hmp.c | 11 ++++++++++ hmp.h | 1 + monitor.c | 57 ------------------------------------------------ qapi-schema.json | 29 ++++++++++++++++++++++++ qmp-commands.hx | 5 +---- qmp.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 97 insertions(+), 63 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index a586498495..4355a6f1e4 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1219,8 +1219,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 diff --git a/hmp.c b/hmp.c index 8a777804de..888e1b96ce 100644 --- a/hmp.c +++ b/hmp.c @@ -681,3 +681,14 @@ 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); +} diff --git a/hmp.h b/hmp.h index 093242d626..4ed0feea66 100644 --- a/hmp.h +++ b/hmp.h @@ -49,5 +49,6 @@ 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); #endif diff --git a/monitor.c b/monitor.c index 759c1335c3..1f5d343d07 100644 --- a/monitor.c +++ b/monitor.c @@ -884,63 +884,6 @@ static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data) 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. */ - rc = vnc_display_password(NULL, password); - if (rc < 0) { - qerror_report(QERR_SET_PASSWD_FAILED); - return -1; - } - return 0; - } - - 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"); diff --git a/qapi-schema.json b/qapi-schema.json index 44cf764ec3..092ff6eac2 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1275,3 +1275,32 @@ { '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'} } diff --git a/qmp-commands.hx b/qmp-commands.hx index 7e3f4b9a59..eadad054cb 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -851,10 +851,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 diff --git a/qmp.c b/qmp.c index c74dde6c90..9ef43a857c 100644 --- a/qmp.c +++ b/qmp.c @@ -16,6 +16,8 @@ #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" @@ -249,3 +251,55 @@ 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"); +} From 9ad5372daa3100d78b12aad59054970f15692a90 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 7 Dec 2011 11:47:57 -0200 Subject: [PATCH 03/14] qapi: Convert expire_password Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- console.h | 2 -- hmp-commands.hx | 3 +-- hmp.c | 10 ++++++++++ hmp.h | 1 + monitor.c | 39 --------------------------------------- qapi-schema.json | 27 +++++++++++++++++++++++++++ qmp-commands.hx | 5 +---- qmp.c | 40 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 80 insertions(+), 47 deletions(-) diff --git a/console.h b/console.h index be3b7c8b4f..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 */ @@ -388,7 +387,6 @@ static inline int vnc_display_password(DisplayState *ds, const char *password) } 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 4355a6f1e4..047fba2eeb 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1239,8 +1239,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 888e1b96ce..081acabd21 100644 --- a/hmp.c +++ b/hmp.c @@ -692,3 +692,13 @@ void hmp_set_password(Monitor *mon, const QDict *qdict) 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); +} diff --git a/hmp.h b/hmp.h index 4ed0feea66..575f529a8d 100644 --- a/hmp.h +++ b/hmp.h @@ -50,5 +50,6 @@ 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); #endif diff --git a/monitor.c b/monitor.c index 1f5d343d07..aa7259c463 100644 --- a/monitor.c +++ b/monitor.c @@ -884,45 +884,6 @@ static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data) return ret; } -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"); diff --git a/qapi-schema.json b/qapi-schema.json index 092ff6eac2..dc92a791e2 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1304,3 +1304,30 @@ ## { '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'} } diff --git a/qmp-commands.hx b/qmp-commands.hx index eadad054cb..d7264b2dbb 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -877,10 +877,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 diff --git a/qmp.c b/qmp.c index 9ef43a857c..8b7b37999d 100644 --- a/qmp.c +++ b/qmp.c @@ -303,3 +303,43 @@ void qmp_set_password(const char *protocol, const char *password, 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"); +} From 92d48558edb14666a2851068db4c2095664e0fbc Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 7 Dec 2011 15:47:23 -0200 Subject: [PATCH 04/14] block: eject_device(): Use error_set() Also drops the leftover 'mon' argument. This is a preparation for the next commits which will port the eject and change commands to the QAPI. Signed-off-by: Luiz Capitulino --- blockdev.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/blockdev.c b/blockdev.c index c832782d03..9ee5bae6cd 100644 --- a/blockdev.c +++ b/blockdev.c @@ -665,21 +665,22 @@ 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) @@ -687,13 +688,22 @@ int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data) BlockDriverState *bs; int force = qdict_get_try_bool(qdict, "force", 0); const char *filename = qdict_get_str(qdict, "device"); + Error *err = NULL; bs = bdrv_find(filename); if (!bs) { qerror_report(QERR_DEVICE_NOT_FOUND, filename); return -1; } - return eject_device(mon, bs, force); + + eject_device(bs, force, &err); + if (error_is_set(&err)) { + qerror_report_err(err); + error_free(err); + return -1; + } + + return 0; } void qmp_block_passwd(const char *device, const char *password, Error **errp) @@ -723,6 +733,7 @@ int do_change_block(Monitor *mon, const char *device, BlockDriverState *bs; BlockDriver *drv = NULL; int bdrv_flags; + Error *err = NULL; bs = bdrv_find(device); if (!bs) { @@ -736,7 +747,10 @@ int do_change_block(Monitor *mon, const char *device, return -1; } } - if (eject_device(mon, bs, 0) < 0) { + eject_device(bs, 0, &err); + if (error_is_set(&err)) { + qerror_report_err(err); + error_free(err); return -1; } bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR; From c245b6a37d76670c3ba7b9063bac943bb998bb7c Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 7 Dec 2011 16:02:36 -0200 Subject: [PATCH 05/14] qapi: Convert eject Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- blockdev.c | 20 +++++--------------- blockdev.h | 1 - hmp-commands.hx | 3 +-- hmp.c | 10 ++++++++++ hmp.h | 1 + qapi-schema.json | 21 +++++++++++++++++++++ qmp-commands.hx | 5 +---- 7 files changed, 39 insertions(+), 22 deletions(-) diff --git a/blockdev.c b/blockdev.c index 9ee5bae6cd..124fbe6c1b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -683,27 +683,17 @@ static void eject_device(BlockDriverState *bs, int force, Error **errp) bdrv_close(bs); } -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"); - Error *err = NULL; - 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; } - eject_device(bs, force, &err); - if (error_is_set(&err)) { - qerror_report_err(err); - error_free(err); - return -1; - } - - return 0; + eject_device(bs, force, errp); } void qmp_block_passwd(const char *device, const char *password, Error **errp) diff --git a/blockdev.h b/blockdev.h index f1b639660d..1937b281c9 100644 --- a/blockdev.h +++ b/blockdev.h @@ -58,7 +58,6 @@ DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi); DriveInfo *add_init_drive(const char *opts); 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); diff --git a/hmp-commands.hx b/hmp-commands.hx index 047fba2eeb..364623c1bd 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 diff --git a/hmp.c b/hmp.c index 081acabd21..a0752f585e 100644 --- a/hmp.c +++ b/hmp.c @@ -702,3 +702,13 @@ void hmp_expire_password(Monitor *mon, const QDict *qdict) 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); +} diff --git a/hmp.h b/hmp.h index 575f529a8d..29dbf93510 100644 --- a/hmp.h +++ b/hmp.h @@ -51,5 +51,6 @@ 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); #endif diff --git a/qapi-schema.json b/qapi-schema.json index dc92a791e2..42682eb2e2 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1331,3 +1331,24 @@ # 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'} } diff --git a/qmp-commands.hx b/qmp-commands.hx index d7264b2dbb..185bebabee 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 From 7060b478d3f3a8bc7a282292609ff5aec6de1958 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 2 Sep 2011 12:34:50 -0500 Subject: [PATCH 06/14] monitor: expose readline state HMP is now implemented in terms of QMP. The monitor has a bunch of logic to deal with HMP right now like readline support. Export it from the monitor so we can consume it in hmp.c. In short time, hmp.c will take over all of the readline bits. Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- monitor.c | 11 ++++++++--- monitor.h | 5 +++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/monitor.c b/monitor.c index aa7259c463..bd4bc4f5b0 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"); @@ -4664,6 +4664,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) 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); From 270b243f91cdae380eb02396e57452c15dbcef86 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 8 Dec 2011 11:45:55 -0200 Subject: [PATCH 07/14] qapi: Introduce change-vnc-password New QMP command to change the VNC password. Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino Signed-off-by: Luiz Capitulino --- qapi-schema.json | 14 ++++++++++++++ qmp-commands.hx | 6 ++++++ qmp.c | 7 +++++++ 3 files changed, 27 insertions(+) diff --git a/qapi-schema.json b/qapi-schema.json index 42682eb2e2..fe935a9d7e 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1352,3 +1352,17 @@ # 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'} } diff --git a/qmp-commands.hx b/qmp-commands.hx index 185bebabee..886d589fd5 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2018,3 +2018,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 8b7b37999d..f218485ef1 100644 --- a/qmp.c +++ b/qmp.c @@ -343,3 +343,10 @@ void qmp_expire_password(const char *protocol, const char *whenstr, error_set(errp, QERR_INVALID_PARAMETER, "protocol"); } + +void qmp_change_vnc_password(const char *password, Error **errp) +{ + if (vnc_display_password(NULL, password) < 0) { + error_set(errp, QERR_SET_PASSWD_FAILED); + } +} From 903a881481745584b538591ea4db92bca7156956 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 13 Dec 2011 17:18:30 -0200 Subject: [PATCH 08/14] qerror: Extend QERR_DEVICE_ENCRYPTED Include the name of the encrypted file. Signed-off-by: Luiz Capitulino --- monitor.c | 3 ++- qerror.h | 2 +- qmp.c | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/monitor.c b/monitor.c index bd4bc4f5b0..f85a9d2499 100644 --- a/monitor.c +++ b/monitor.c @@ -4682,7 +4682,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/qerror.h b/qerror.h index efda232db3..27800fe10f 100644 --- a/qerror.h +++ b/qerror.h @@ -70,7 +70,7 @@ QError *qobject_to_qerror(const QObject *obj); "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }" #define QERR_DEVICE_ENCRYPTED \ - "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s } }" + "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }" #define QERR_DEVICE_INIT_FAILED \ "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }" diff --git a/qmp.c b/qmp.c index f218485ef1..9c9ea629ed 100644 --- a/qmp.c +++ b/qmp.c @@ -135,7 +135,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)); } } From 333a96ec9fd08eaa03f8de1acc41a2851ccb8096 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 8 Dec 2011 11:13:50 -0200 Subject: [PATCH 09/14] qapi: Convert change Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- blockdev.c | 54 ++++++++++++++++++++++++----------- blockdev.h | 5 ++-- hmp-commands.hx | 3 +- hmp.c | 57 +++++++++++++++++++++++++++++++++++++ hmp.h | 1 + monitor.c | 74 ------------------------------------------------ qapi-schema.json | 36 +++++++++++++++++++++++ qmp-commands.hx | 5 +--- qmp.c | 44 ++++++++++++++++++++++++++++ 9 files changed, 181 insertions(+), 98 deletions(-) diff --git a/blockdev.c b/blockdev.c index 124fbe6c1b..8df78ceb7b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -717,8 +717,31 @@ 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; @@ -727,29 +750,28 @@ int do_change_block(Monitor *mon, const char *device, 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; } } + eject_device(bs, 0, &err); if (error_is_set(&err)) { - qerror_report_err(err); - error_free(err); - return -1; + 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 */ diff --git a/blockdev.h b/blockdev.h index 1937b281c9..b077449dcd 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,9 +58,9 @@ 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_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); diff --git a/hmp-commands.hx b/hmp-commands.hx index 364623c1bd..ac27ab379c 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -107,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 diff --git a/hmp.c b/hmp.c index a0752f585e..2b948aad05 100644 --- a/hmp.c +++ b/hmp.c @@ -712,3 +712,60 @@ void hmp_eject(Monitor *mon, const QDict *qdict) 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); +} diff --git a/hmp.h b/hmp.h index 29dbf93510..621bdc20f7 100644 --- a/hmp.h +++ b/hmp.h @@ -52,5 +52,6 @@ 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); #endif diff --git a/monitor.c b/monitor.c index f85a9d2499..187083c450 100644 --- a/monitor.c +++ b/monitor.c @@ -810,80 +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 add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data) { const char *protocol = qdict_get_str(qdict, "protocol"); diff --git a/qapi-schema.json b/qapi-schema.json index fe935a9d7e..eb20dacf17 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1366,3 +1366,39 @@ # 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'} } diff --git a/qmp-commands.hx b/qmp-commands.hx index 886d589fd5..bfae81ff3d 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -110,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 diff --git a/qmp.c b/qmp.c index 9c9ea629ed..1222b6c9c4 100644 --- a/qmp.c +++ b/qmp.c @@ -23,6 +23,7 @@ #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) { @@ -345,9 +346,52 @@ void qmp_expire_password(const char *protocol, const char *whenstr, 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); + } +} From 80047da59b17053b69e8bdc143c8fb4b3a44cb7d Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 14 Dec 2011 16:49:14 -0200 Subject: [PATCH 10/14] qapi: Convert block_set_io_throttle Signed-off-by: Luiz Capitulino --- blockdev.c | 47 ++++++++++++++--------------------------------- blockdev.h | 2 -- hmp-commands.hx | 3 +-- hmp.c | 14 ++++++++++++++ hmp.h | 1 + qapi-schema.json | 29 +++++++++++++++++++++++++++++ qmp-commands.hx | 5 +---- 7 files changed, 60 insertions(+), 41 deletions(-) diff --git a/blockdev.c b/blockdev.c index 8df78ceb7b..5d16137878 100644 --- a/blockdev.c +++ b/blockdev.c @@ -775,46 +775,29 @@ void qmp_change_blockdev(const char *device, const char *filename, } /* 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; @@ -829,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) diff --git a/blockdev.h b/blockdev.h index b077449dcd..260e16b3c6 100644 --- a/blockdev.h +++ b/blockdev.h @@ -62,6 +62,4 @@ 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_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/hmp-commands.hx b/hmp-commands.hx index ac27ab379c..e6506fc9d3 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1202,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 diff --git a/hmp.c b/hmp.c index 2b948aad05..4664dbe8e4 100644 --- a/hmp.c +++ b/hmp.c @@ -769,3 +769,17 @@ void hmp_change(Monitor *mon, const QDict *qdict) } 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 621bdc20f7..aab0b1f508 100644 --- a/hmp.h +++ b/hmp.h @@ -53,5 +53,6 @@ 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/qapi-schema.json b/qapi-schema.json index eb20dacf17..9b154ccda3 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1402,3 +1402,32 @@ ## { '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/qmp-commands.hx b/qmp-commands.hx index bfae81ff3d..799e655988 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -807,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 From aba2107a2649f3eeab4422efa17dbd06929abccd Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 23 Dec 2011 20:34:38 +0100 Subject: [PATCH 11/14] qmp: Add missing gcc format attribute and fix format string Signed-off-by: Stefan Weil Reviewed-by: Stefan Hajnoczi Signed-off-by: Luiz Capitulino --- test-qmp-input-visitor.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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)); From 9737383beb515a583fdb6f2aafa631fcd6797068 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 4 Jan 2012 22:23:32 +0000 Subject: [PATCH 12/14] qerror: add check-qerror.sh to verify alphabetical order We're supposed to keep qerror definitions and table entries in alphabetical order. In practice this is not checked. I haven't found a nice way to integrate this into the makefile yet but we can at least have this script which verifies that qerrors are in alphabetical order. Signed-off-by: Stefan Hajnoczi Signed-off-by: Luiz Capitulino --- qerror.c | 3 +-- qerror.h | 2 +- scripts/check-qerror.sh | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100755 scripts/check-qerror.sh diff --git a/qerror.c b/qerror.c index 9a75d06301..62c0c707b5 100644 --- a/qerror.c +++ b/qerror.c @@ -40,8 +40,7 @@ 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[] = { { diff --git a/qerror.h b/qerror.h index 27800fe10f..40e52e8c51 100644 --- a/qerror.h +++ b/qerror.h @@ -49,7 +49,7 @@ 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_BAD_BUS_FOR_DEVICE \ "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }" 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 From c1303596a196613f1a765f8a536319577b2bb844 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 4 Jan 2012 17:38:22 +0000 Subject: [PATCH 13/14] qerror: restore alphabetical order over qerrors Over time these must have gotten out of order. Put everything back in alphabetical order. This is purely a clean up. In practice nothing depends on the order. Signed-off-by: Stefan Hajnoczi Signed-off-by: Luiz Capitulino --- qerror.c | 84 ++++++++++++++++++++++++++++---------------------------- qerror.h | 72 ++++++++++++++++++++++++------------------------ 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/qerror.c b/qerror.c index 62c0c707b5..2979b3ef7f 100644 --- a/qerror.c +++ b/qerror.c @@ -43,6 +43,10 @@ static const QType qerror_type = { * 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", @@ -51,26 +55,30 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, .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_INIT_FAILED, .desc = "Device '%(device)' could not be initialized", @@ -79,10 +87,6 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_DEVICE_IN_USE, .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_LOCKED, .desc = "Device '%(device)' is locked", @@ -91,6 +95,14 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_DEVICE_MULTIPLE_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, .desc = "Device '%(device)' has not been activated", @@ -107,14 +119,6 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_DEVICE_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, .desc = "Duplicate ID '%(id)' for %(object)", @@ -139,6 +143,10 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_INVALID_PARAMETER, .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)", @@ -155,15 +163,15 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_IO_ERROR, .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", @@ -209,6 +217,14 @@ static const QErrorStringTable qerror_table[] = { .desc = "Property '%(device).%(property)' doesn't take " "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", @@ -229,10 +245,6 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_SET_PASSWD_FAILED, .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", @@ -241,15 +253,15 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_UNDEFINED_ERROR, .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)' " @@ -259,18 +271,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 40e52e8c51..be4e8657aa 100644 --- a/qerror.h +++ b/qerror.h @@ -51,42 +51,54 @@ QError *qobject_to_qerror(const QObject *obj); * Please keep the definitions in alphabetical order. * 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, 'filename': %s } }" +#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \ + "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }" + #define QERR_DEVICE_INIT_FAILED \ "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }" #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_LOCKED \ "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }" #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 +111,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 +120,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 +144,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 +183,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 +204,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 */ From 939a1cc399adb92640d156097d528b6471c136ae Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 4 Jan 2012 22:23:34 +0000 Subject: [PATCH 14/14] block: use proper qerrors in qmp_block_resize Let's report specific errors so that management tools and users can identify the problem. Two new qerrors are needed: * QERR_DEVICE_HAS_NO_MEDIUM for ENOMEDIUM * QERR_DEVICE_IS_READ_ONLY for EACCES Signed-off-by: Stefan Hajnoczi Signed-off-by: Luiz Capitulino --- blockdev.c | 26 ++++++++++++++++++-------- qapi-schema.json | 7 +++++-- qerror.c | 8 ++++++++ qerror.h | 6 ++++++ 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/blockdev.c b/blockdev.c index 5d16137878..1f83c888e7 100644 --- a/blockdev.c +++ b/blockdev.c @@ -848,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; @@ -864,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/qapi-schema.json b/qapi-schema.json index 9b154ccda3..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 ## diff --git a/qerror.c b/qerror.c index 2979b3ef7f..3d95383940 100644 --- a/qerror.c +++ b/qerror.c @@ -79,6 +79,10 @@ static const QErrorStringTable qerror_table[] = { .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", @@ -87,6 +91,10 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_DEVICE_IN_USE, .desc = "Device '%(device)' is in use", }, + { + .error_fmt = QERR_DEVICE_IS_READ_ONLY, + .desc = "Device '%(device)' is read only", + }, { .error_fmt = QERR_DEVICE_LOCKED, .desc = "Device '%(device)' is locked", diff --git a/qerror.h b/qerror.h index be4e8657aa..89160dd78e 100644 --- a/qerror.h +++ b/qerror.h @@ -81,12 +81,18 @@ QError *qobject_to_qerror(const QObject *obj); #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 } }" #define QERR_DEVICE_IN_USE \ "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }" +#define QERR_DEVICE_IS_READ_ONLY \ + "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }" + #define QERR_DEVICE_LOCKED \ "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"