Merge remote-tracking branch 'qmp/queue/qmp' into staging
* qmp/queue/qmp: block: use proper qerrors in qmp_block_resize qerror: restore alphabetical order over qerrors qerror: add check-qerror.sh to verify alphabetical order qmp: Add missing gcc format attribute and fix format string qapi: Convert block_set_io_throttle qapi: Convert change qerror: Extend QERR_DEVICE_ENCRYPTED qapi: Introduce change-vnc-password monitor: expose readline state qapi: Convert eject block: eject_device(): Use error_set() qapi: Convert expire_password qapi: Convert set_password vnc: Simplify vnc_display_password()
This commit is contained in:
commit
b48c0134de
155
blockdev.c
155
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
102
hmp.c
102
hmp.c
|
@ -681,3 +681,105 @@ void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
|
|||
int64_t value = qdict_get_int(qdict, "value");
|
||||
qmp_migrate_set_speed(value, NULL);
|
||||
}
|
||||
|
||||
void hmp_set_password(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *protocol = qdict_get_str(qdict, "protocol");
|
||||
const char *password = qdict_get_str(qdict, "password");
|
||||
const char *connected = qdict_get_try_str(qdict, "connected");
|
||||
Error *err = NULL;
|
||||
|
||||
qmp_set_password(protocol, password, !!connected, connected, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
||||
void hmp_expire_password(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *protocol = qdict_get_str(qdict, "protocol");
|
||||
const char *whenstr = qdict_get_str(qdict, "time");
|
||||
Error *err = NULL;
|
||||
|
||||
qmp_expire_password(protocol, whenstr, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
||||
void hmp_eject(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
int force = qdict_get_try_bool(qdict, "force", 0);
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
Error *err = NULL;
|
||||
|
||||
qmp_eject(device, true, force, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
||||
static void hmp_change_read_arg(Monitor *mon, const char *password,
|
||||
void *opaque)
|
||||
{
|
||||
qmp_change_vnc_password(password, NULL);
|
||||
monitor_read_command(mon, 1);
|
||||
}
|
||||
|
||||
static void cb_hmp_change_bdrv_pwd(Monitor *mon, const char *password,
|
||||
void *opaque)
|
||||
{
|
||||
Error *encryption_err = opaque;
|
||||
Error *err = NULL;
|
||||
const char *device;
|
||||
|
||||
device = error_get_field(encryption_err, "device");
|
||||
|
||||
qmp_block_passwd(device, password, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
error_free(encryption_err);
|
||||
|
||||
monitor_read_command(mon, 1);
|
||||
}
|
||||
|
||||
void hmp_change(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
const char *target = qdict_get_str(qdict, "target");
|
||||
const char *arg = qdict_get_try_str(qdict, "arg");
|
||||
Error *err = NULL;
|
||||
|
||||
if (strcmp(device, "vnc") == 0 &&
|
||||
(strcmp(target, "passwd") == 0 ||
|
||||
strcmp(target, "password") == 0)) {
|
||||
if (!arg) {
|
||||
monitor_read_password(mon, hmp_change_read_arg, NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
qmp_change(device, target, !!arg, arg, &err);
|
||||
if (error_is_type(err, QERR_DEVICE_ENCRYPTED)) {
|
||||
monitor_printf(mon, "%s (%s) is encrypted.\n",
|
||||
error_get_field(err, "device"),
|
||||
error_get_field(err, "filename"));
|
||||
if (!monitor_get_rs(mon)) {
|
||||
monitor_printf(mon,
|
||||
"terminal does not support password prompting\n");
|
||||
error_free(err);
|
||||
return;
|
||||
}
|
||||
readline_start(monitor_get_rs(mon), "Password: ", 1,
|
||||
cb_hmp_change_bdrv_pwd, err);
|
||||
return;
|
||||
}
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
||||
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *err = NULL;
|
||||
|
||||
qmp_block_set_io_throttle(qdict_get_str(qdict, "device"),
|
||||
qdict_get_int(qdict, "bps"),
|
||||
qdict_get_int(qdict, "bps_rd"),
|
||||
qdict_get_int(qdict, "bps_wr"),
|
||||
qdict_get_int(qdict, "iops"),
|
||||
qdict_get_int(qdict, "iops_rd"),
|
||||
qdict_get_int(qdict, "iops_wr"), &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
|
5
hmp.h
5
hmp.h
|
@ -49,5 +49,10 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
|
|||
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
|
||||
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
|
||||
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
|
||||
void hmp_set_password(Monitor *mon, const QDict *qdict);
|
||||
void hmp_expire_password(Monitor *mon, const QDict *qdict);
|
||||
void hmp_eject(Monitor *mon, const QDict *qdict);
|
||||
void hmp_change(Monitor *mon, const QDict *qdict);
|
||||
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#endif
|
||||
|
|
179
monitor.c
179
monitor.c
|
@ -227,7 +227,7 @@ int monitor_cur_is_qmp(void)
|
|||
return cur_mon && monitor_ctrl_mode(cur_mon);
|
||||
}
|
||||
|
||||
static void monitor_read_command(Monitor *mon, int show_prompt)
|
||||
void monitor_read_command(Monitor *mon, int show_prompt)
|
||||
{
|
||||
if (!mon->rs)
|
||||
return;
|
||||
|
@ -237,8 +237,8 @@ static void monitor_read_command(Monitor *mon, int show_prompt)
|
|||
readline_show_prompt(mon->rs);
|
||||
}
|
||||
|
||||
static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
|
||||
void *opaque)
|
||||
int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
|
||||
void *opaque)
|
||||
{
|
||||
if (monitor_ctrl_mode(mon)) {
|
||||
qerror_report(QERR_MISSING_PARAMETER, "password");
|
||||
|
@ -810,171 +810,6 @@ static void do_trace_print_events(Monitor *mon)
|
|||
trace_print_events((FILE *)mon, &monitor_fprintf);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VNC
|
||||
static int change_vnc_password(const char *password)
|
||||
{
|
||||
if (!password || !password[0]) {
|
||||
if (vnc_display_disable_login(NULL)) {
|
||||
qerror_report(QERR_SET_PASSWD_FAILED);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vnc_display_password(NULL, password) < 0) {
|
||||
qerror_report(QERR_SET_PASSWD_FAILED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void change_vnc_password_cb(Monitor *mon, const char *password,
|
||||
void *opaque)
|
||||
{
|
||||
change_vnc_password(password);
|
||||
monitor_read_command(mon, 1);
|
||||
}
|
||||
|
||||
static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
|
||||
{
|
||||
if (strcmp(target, "passwd") == 0 ||
|
||||
strcmp(target, "password") == 0) {
|
||||
if (arg) {
|
||||
char password[9];
|
||||
strncpy(password, arg, sizeof(password));
|
||||
password[sizeof(password) - 1] = '\0';
|
||||
return change_vnc_password(password);
|
||||
} else {
|
||||
return monitor_read_password(mon, change_vnc_password_cb, NULL);
|
||||
}
|
||||
} else {
|
||||
if (vnc_display_open(NULL, target) < 0) {
|
||||
qerror_report(QERR_VNC_SERVER_FAILED, target);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
|
||||
{
|
||||
qerror_report(QERR_FEATURE_DISABLED, "vnc");
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* do_change(): Change a removable medium, or VNC configuration
|
||||
*/
|
||||
static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
const char *target = qdict_get_str(qdict, "target");
|
||||
const char *arg = qdict_get_try_str(qdict, "arg");
|
||||
int ret;
|
||||
|
||||
if (strcmp(device, "vnc") == 0) {
|
||||
ret = do_change_vnc(mon, target, arg);
|
||||
} else {
|
||||
ret = do_change_block(mon, device, target, arg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
const char *protocol = qdict_get_str(qdict, "protocol");
|
||||
const char *password = qdict_get_str(qdict, "password");
|
||||
const char *connected = qdict_get_try_str(qdict, "connected");
|
||||
int disconnect_if_connected = 0;
|
||||
int fail_if_connected = 0;
|
||||
int rc;
|
||||
|
||||
if (connected) {
|
||||
if (strcmp(connected, "fail") == 0) {
|
||||
fail_if_connected = 1;
|
||||
} else if (strcmp(connected, "disconnect") == 0) {
|
||||
disconnect_if_connected = 1;
|
||||
} else if (strcmp(connected, "keep") == 0) {
|
||||
/* nothing */
|
||||
} else {
|
||||
qerror_report(QERR_INVALID_PARAMETER, "connected");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(protocol, "spice") == 0) {
|
||||
if (!using_spice) {
|
||||
/* correct one? spice isn't a device ,,, */
|
||||
qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
|
||||
return -1;
|
||||
}
|
||||
rc = qemu_spice_set_passwd(password, fail_if_connected,
|
||||
disconnect_if_connected);
|
||||
if (rc != 0) {
|
||||
qerror_report(QERR_SET_PASSWD_FAILED);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(protocol, "vnc") == 0) {
|
||||
if (fail_if_connected || disconnect_if_connected) {
|
||||
/* vnc supports "connected=keep" only */
|
||||
qerror_report(QERR_INVALID_PARAMETER, "connected");
|
||||
return -1;
|
||||
}
|
||||
/* Note that setting an empty password will not disable login through
|
||||
* this interface. */
|
||||
return vnc_display_password(NULL, password);
|
||||
}
|
||||
|
||||
qerror_report(QERR_INVALID_PARAMETER, "protocol");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
const char *protocol = qdict_get_str(qdict, "protocol");
|
||||
const char *whenstr = qdict_get_str(qdict, "time");
|
||||
time_t when;
|
||||
int rc;
|
||||
|
||||
if (strcmp(whenstr, "now") == 0) {
|
||||
when = 0;
|
||||
} else if (strcmp(whenstr, "never") == 0) {
|
||||
when = TIME_MAX;
|
||||
} else if (whenstr[0] == '+') {
|
||||
when = time(NULL) + strtoull(whenstr+1, NULL, 10);
|
||||
} else {
|
||||
when = strtoull(whenstr, NULL, 10);
|
||||
}
|
||||
|
||||
if (strcmp(protocol, "spice") == 0) {
|
||||
if (!using_spice) {
|
||||
/* correct one? spice isn't a device ,,, */
|
||||
qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
|
||||
return -1;
|
||||
}
|
||||
rc = qemu_spice_set_pw_expire(when);
|
||||
if (rc != 0) {
|
||||
qerror_report(QERR_SET_PASSWD_FAILED);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(protocol, "vnc") == 0) {
|
||||
return vnc_display_pw_expire(NULL, when);
|
||||
}
|
||||
|
||||
qerror_report(QERR_INVALID_PARAMETER, "protocol");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
const char *protocol = qdict_get_str(qdict, "protocol");
|
||||
|
@ -4755,6 +4590,11 @@ static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
|
|||
monitor_read_command(mon, 1);
|
||||
}
|
||||
|
||||
ReadLineState *monitor_get_rs(Monitor *mon)
|
||||
{
|
||||
return mon->rs;
|
||||
}
|
||||
|
||||
int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *completion_cb,
|
||||
void *opaque)
|
||||
|
@ -4768,7 +4608,8 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
|
|||
}
|
||||
|
||||
if (monitor_ctrl_mode(mon)) {
|
||||
qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
|
||||
qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
|
||||
bdrv_get_encrypted_filename(bs));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
163
qapi-schema.json
163
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' } }
|
||||
|
|
91
qerror.c
91
qerror.c
|
@ -40,10 +40,13 @@ 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",
|
||||
|
@ -52,26 +55,34 @@ 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_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,
|
||||
|
@ -92,6 +103,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",
|
||||
|
@ -108,14 +127,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)",
|
||||
|
@ -140,6 +151,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)",
|
||||
|
@ -156,15 +171,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",
|
||||
|
@ -210,6 +225,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",
|
||||
|
@ -230,10 +253,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",
|
||||
|
@ -242,15 +261,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)' "
|
||||
|
@ -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",
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
80
qerror.h
80
qerror.h
|
@ -49,28 +49,40 @@ QError *qobject_to_qerror(const QObject *obj);
|
|||
/*
|
||||
* QError class list
|
||||
* Please keep the definitions in alphabetical order.
|
||||
* Use "grep '^#define QERR_' qerror.h | sort -c" to check.
|
||||
* Use scripts/check-qerror.sh to check.
|
||||
*/
|
||||
#define QERR_ADD_CLIENT_FAILED \
|
||||
"{ 'class': 'AddClientFailed', 'data': {} }"
|
||||
|
||||
#define QERR_BAD_BUS_FOR_DEVICE \
|
||||
"{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
|
||||
|
||||
#define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
|
||||
"{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
|
||||
|
||||
#define QERR_BUS_NOT_FOUND \
|
||||
"{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
|
||||
#define QERR_BUFFER_OVERRUN \
|
||||
"{ 'class': 'BufferOverrun', 'data': {} }"
|
||||
|
||||
#define QERR_BUS_NO_HOTPLUG \
|
||||
"{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
|
||||
|
||||
#define QERR_COMMAND_NOT_FOUND \
|
||||
"{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
|
||||
#define QERR_BUS_NOT_FOUND \
|
||||
"{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
|
||||
|
||||
#define QERR_COMMAND_DISABLED \
|
||||
"{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
|
||||
|
||||
#define QERR_COMMAND_NOT_FOUND \
|
||||
"{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
|
||||
|
||||
#define QERR_DEVICE_ENCRYPTED \
|
||||
"{ 'class': 'DeviceEncrypted', 'data': { 'device': %s } }"
|
||||
"{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
|
||||
|
||||
#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
|
||||
"{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
|
||||
|
||||
#define QERR_DEVICE_HAS_NO_MEDIUM \
|
||||
"{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }"
|
||||
|
||||
#define QERR_DEVICE_INIT_FAILED \
|
||||
"{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
|
||||
|
@ -78,8 +90,8 @@ QError *qobject_to_qerror(const QObject *obj);
|
|||
#define QERR_DEVICE_IN_USE \
|
||||
"{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
|
||||
|
||||
#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
|
||||
"{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
|
||||
#define QERR_DEVICE_IS_READ_ONLY \
|
||||
"{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
|
||||
|
||||
#define QERR_DEVICE_LOCKED \
|
||||
"{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
|
||||
|
@ -87,6 +99,12 @@ QError *qobject_to_qerror(const QObject *obj);
|
|||
#define QERR_DEVICE_MULTIPLE_BUSSES \
|
||||
"{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
|
||||
|
||||
#define QERR_DEVICE_NO_BUS \
|
||||
"{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
|
||||
|
||||
#define QERR_DEVICE_NO_HOTPLUG \
|
||||
"{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
|
||||
|
||||
#define QERR_DEVICE_NOT_ACTIVE \
|
||||
"{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
|
||||
|
||||
|
@ -99,12 +117,6 @@ QError *qobject_to_qerror(const QObject *obj);
|
|||
#define QERR_DEVICE_NOT_REMOVABLE \
|
||||
"{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
|
||||
|
||||
#define QERR_DEVICE_NO_BUS \
|
||||
"{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
|
||||
|
||||
#define QERR_DEVICE_NO_HOTPLUG \
|
||||
"{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
|
||||
|
||||
#define QERR_DUPLICATE_ID \
|
||||
"{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
|
||||
|
||||
|
@ -114,12 +126,18 @@ QError *qobject_to_qerror(const QObject *obj);
|
|||
#define QERR_FD_NOT_SUPPLIED \
|
||||
"{ 'class': 'FdNotSupplied', 'data': {} }"
|
||||
|
||||
#define QERR_FEATURE_DISABLED \
|
||||
"{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
|
||||
|
||||
#define QERR_INVALID_BLOCK_FORMAT \
|
||||
"{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
|
||||
|
||||
#define QERR_INVALID_PARAMETER \
|
||||
"{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
|
||||
|
||||
#define QERR_INVALID_PARAMETER_COMBINATION \
|
||||
"{ 'class': 'InvalidParameterCombination', 'data': {} }"
|
||||
|
||||
#define QERR_INVALID_PARAMETER_TYPE \
|
||||
"{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
|
||||
|
||||
|
@ -132,14 +150,11 @@ QError *qobject_to_qerror(const QObject *obj);
|
|||
#define QERR_IO_ERROR \
|
||||
"{ 'class': 'IOError', 'data': {} }"
|
||||
|
||||
#define QERR_JSON_PARSING \
|
||||
"{ 'class': 'JSONParsing', 'data': {} }"
|
||||
|
||||
#define QERR_JSON_PARSE_ERROR \
|
||||
"{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
|
||||
|
||||
#define QERR_BUFFER_OVERRUN \
|
||||
"{ 'class': 'BufferOverrun', 'data': {} }"
|
||||
#define QERR_JSON_PARSING \
|
||||
"{ 'class': 'JSONParsing', 'data': {} }"
|
||||
|
||||
#define QERR_KVM_MISSING_CAP \
|
||||
"{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
|
||||
|
@ -174,6 +189,12 @@ QError *qobject_to_qerror(const QObject *obj);
|
|||
#define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
|
||||
"{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
|
||||
|
||||
#define QERR_QGA_COMMAND_FAILED \
|
||||
"{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
|
||||
|
||||
#define QERR_QGA_LOGGING_FAILED \
|
||||
"{ 'class': 'QgaLoggingFailed', 'data': {} }"
|
||||
|
||||
#define QERR_QMP_BAD_INPUT_OBJECT \
|
||||
"{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
|
||||
|
||||
|
@ -189,37 +210,22 @@ QError *qobject_to_qerror(const QObject *obj);
|
|||
#define QERR_SET_PASSWD_FAILED \
|
||||
"{ 'class': 'SetPasswdFailed', 'data': {} }"
|
||||
|
||||
#define QERR_ADD_CLIENT_FAILED \
|
||||
"{ 'class': 'AddClientFailed', 'data': {} }"
|
||||
|
||||
#define QERR_TOO_MANY_FILES \
|
||||
"{ 'class': 'TooManyFiles', 'data': {} }"
|
||||
|
||||
#define QERR_UNDEFINED_ERROR \
|
||||
"{ 'class': 'UndefinedError', 'data': {} }"
|
||||
|
||||
#define QERR_UNSUPPORTED \
|
||||
"{ 'class': 'Unsupported', 'data': {} }"
|
||||
|
||||
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
|
||||
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
|
||||
|
||||
#define QERR_UNSUPPORTED \
|
||||
"{ 'class': 'Unsupported', 'data': {} }"
|
||||
|
||||
#define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
|
||||
"{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
|
||||
|
||||
#define QERR_VNC_SERVER_FAILED \
|
||||
"{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
|
||||
|
||||
#define QERR_FEATURE_DISABLED \
|
||||
"{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
|
||||
|
||||
#define QERR_QGA_LOGGING_FAILED \
|
||||
"{ 'class': 'QgaLoggingFailed', 'data': {} }"
|
||||
|
||||
#define QERR_QGA_COMMAND_FAILED \
|
||||
"{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
|
||||
|
||||
#define QERR_INVALID_PARAMETER_COMBINATION \
|
||||
"{ 'class': 'InvalidParameterCombination', 'data': {} }"
|
||||
|
||||
#endif /* QERROR_H */
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
148
qmp.c
148
qmp.c
|
@ -16,11 +16,14 @@
|
|||
#include "qemu-common.h"
|
||||
#include "sysemu.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "ui/qemu-spice.h"
|
||||
#include "ui/vnc.h"
|
||||
#include "kvm.h"
|
||||
#include "arch_init.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "qapi/qmp-input-visitor.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "blockdev.h"
|
||||
|
||||
NameInfo *qmp_query_name(Error **errp)
|
||||
{
|
||||
|
@ -133,7 +136,8 @@ static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
|
|||
Error **err = opaque;
|
||||
|
||||
if (!error_is_set(err) && bdrv_key_required(bs)) {
|
||||
error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
|
||||
error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
|
||||
bdrv_get_encrypted_filename(bs));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,3 +253,145 @@ out:
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qmp_set_password(const char *protocol, const char *password,
|
||||
bool has_connected, const char *connected, Error **errp)
|
||||
{
|
||||
int disconnect_if_connected = 0;
|
||||
int fail_if_connected = 0;
|
||||
int rc;
|
||||
|
||||
if (has_connected) {
|
||||
if (strcmp(connected, "fail") == 0) {
|
||||
fail_if_connected = 1;
|
||||
} else if (strcmp(connected, "disconnect") == 0) {
|
||||
disconnect_if_connected = 1;
|
||||
} else if (strcmp(connected, "keep") == 0) {
|
||||
/* nothing */
|
||||
} else {
|
||||
error_set(errp, QERR_INVALID_PARAMETER, "connected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(protocol, "spice") == 0) {
|
||||
if (!using_spice) {
|
||||
/* correct one? spice isn't a device ,,, */
|
||||
error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
|
||||
return;
|
||||
}
|
||||
rc = qemu_spice_set_passwd(password, fail_if_connected,
|
||||
disconnect_if_connected);
|
||||
if (rc != 0) {
|
||||
error_set(errp, QERR_SET_PASSWD_FAILED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(protocol, "vnc") == 0) {
|
||||
if (fail_if_connected || disconnect_if_connected) {
|
||||
/* vnc supports "connected=keep" only */
|
||||
error_set(errp, QERR_INVALID_PARAMETER, "connected");
|
||||
return;
|
||||
}
|
||||
/* Note that setting an empty password will not disable login through
|
||||
* this interface. */
|
||||
rc = vnc_display_password(NULL, password);
|
||||
if (rc < 0) {
|
||||
error_set(errp, QERR_SET_PASSWD_FAILED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
error_set(errp, QERR_INVALID_PARAMETER, "protocol");
|
||||
}
|
||||
|
||||
void qmp_expire_password(const char *protocol, const char *whenstr,
|
||||
Error **errp)
|
||||
{
|
||||
time_t when;
|
||||
int rc;
|
||||
|
||||
if (strcmp(whenstr, "now") == 0) {
|
||||
when = 0;
|
||||
} else if (strcmp(whenstr, "never") == 0) {
|
||||
when = TIME_MAX;
|
||||
} else if (whenstr[0] == '+') {
|
||||
when = time(NULL) + strtoull(whenstr+1, NULL, 10);
|
||||
} else {
|
||||
when = strtoull(whenstr, NULL, 10);
|
||||
}
|
||||
|
||||
if (strcmp(protocol, "spice") == 0) {
|
||||
if (!using_spice) {
|
||||
/* correct one? spice isn't a device ,,, */
|
||||
error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
|
||||
return;
|
||||
}
|
||||
rc = qemu_spice_set_pw_expire(when);
|
||||
if (rc != 0) {
|
||||
error_set(errp, QERR_SET_PASSWD_FAILED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(protocol, "vnc") == 0) {
|
||||
rc = vnc_display_pw_expire(NULL, when);
|
||||
if (rc != 0) {
|
||||
error_set(errp, QERR_SET_PASSWD_FAILED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
error_set(errp, QERR_INVALID_PARAMETER, "protocol");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VNC
|
||||
void qmp_change_vnc_password(const char *password, Error **errp)
|
||||
{
|
||||
if (vnc_display_password(NULL, password) < 0) {
|
||||
error_set(errp, QERR_SET_PASSWD_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
static void qmp_change_vnc_listen(const char *target, Error **err)
|
||||
{
|
||||
if (vnc_display_open(NULL, target) < 0) {
|
||||
error_set(err, QERR_VNC_SERVER_FAILED, target);
|
||||
}
|
||||
}
|
||||
|
||||
static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
|
||||
Error **errp)
|
||||
{
|
||||
if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) {
|
||||
if (!has_arg) {
|
||||
error_set(errp, QERR_MISSING_PARAMETER, "password");
|
||||
} else {
|
||||
qmp_change_vnc_password(arg, errp);
|
||||
}
|
||||
} else {
|
||||
qmp_change_vnc_listen(target, errp);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void qmp_change_vnc_password(const char *password, Error **errp)
|
||||
{
|
||||
error_set(errp, QERR_FEATURE_DISABLED, "vnc");
|
||||
}
|
||||
static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
|
||||
Error **errp)
|
||||
{
|
||||
error_set(errp, QERR_FEATURE_DISABLED, "vnc");
|
||||
}
|
||||
#endif /* !CONFIG_VNC */
|
||||
|
||||
void qmp_change(const char *device, const char *target,
|
||||
bool has_arg, const char *arg, Error **err)
|
||||
{
|
||||
if (strcmp(device, "vnc") == 0) {
|
||||
qmp_change_vnc(target, has_arg, arg, err);
|
||||
} else {
|
||||
qmp_change_blockdev(device, target, has_arg, arg, err);
|
||||
}
|
||||
}
|
||||
|
|
22
scripts/check-qerror.sh
Executable file
22
scripts/check-qerror.sh
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/bin/sh
|
||||
# This script verifies that qerror definitions and table entries are
|
||||
# alphabetically ordered.
|
||||
|
||||
check_order() {
|
||||
errmsg=$1
|
||||
shift
|
||||
|
||||
# sort -C verifies order but does not print a message. sort -c does print a
|
||||
# message. These options are both in POSIX.
|
||||
if ! "$@" | sort -C; then
|
||||
echo "$errmsg"
|
||||
"$@" | sort -c
|
||||
exit 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
check_order 'Definitions in qerror.h must be in alphabetical order:' \
|
||||
grep '^#define QERR_' qerror.h
|
||||
check_order 'Entries in qerror.c:qerror_table must be in alphabetical order:' \
|
||||
sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c
|
|
@ -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));
|
||||
|
|
14
ui/vnc.c
14
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)
|
||||
|
|
Loading…
Reference in a new issue