diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2012-01-19 09:23:16 -0600 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2012-01-19 09:23:16 -0600 |
commit | b48c0134de96f3deed15a0e115d58f3cff09f3c1 (patch) | |
tree | 2df65714d6e3282b5f6478264e2cc0c57ab7cfa2 | |
parent | 5414b32542662976c364b58011c4841304569aff (diff) | |
parent | 939a1cc399adb92640d156097d528b6471c136ae (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.c | 155 | ||||
-rw-r--r-- | blockdev.h | 8 | ||||
-rw-r--r-- | console.h | 3 | ||||
-rw-r--r-- | hmp-commands.hx | 15 | ||||
-rw-r--r-- | hmp.c | 102 | ||||
-rw-r--r-- | hmp.h | 5 | ||||
-rw-r--r-- | monitor.c | 179 | ||||
-rw-r--r-- | monitor.h | 5 | ||||
-rw-r--r-- | qapi-schema.json | 163 | ||||
-rw-r--r-- | qerror.c | 91 | ||||
-rw-r--r-- | qerror.h | 80 | ||||
-rw-r--r-- | qmp-commands.hx | 31 | ||||
-rw-r--r-- | qmp.c | 148 | ||||
-rwxr-xr-x | scripts/check-qerror.sh | 22 | ||||
-rw-r--r-- | test-qmp-input-visitor.c | 7 | ||||
-rw-r--r-- | ui/vnc.c | 14 |
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 @@ -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 @@ -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); +} @@ -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 @@ -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; } @@ -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' } } @@ -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", - }, {} }; @@ -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, + }, @@ -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)); @@ -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) |