Skip to content

Commit

Permalink
monitor: Rework modal password input (Jan Kiszka)
Browse files Browse the repository at this point in the history
Currently, waiting for the user to type in some password blocks the
whole VM because monitor_readline starts its own I/O loop. And this loop
also screws up reading passwords from virtual console.

Patch below fixes the shortcomings by using normal I/O processing also
for waiting on a password. To keep to modal property for the monitor
terminal, the command handler is temporarily replaced by a password
handler and a callback infrastructure is established to process the
result before switching back to command mode.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6710 c046a42c-6fe2-441c-8c8c-71466251a162
  • Loading branch information
aliguori committed Mar 5, 2009
1 parent 9dd442b commit bb5fc20
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 65 deletions.
21 changes: 15 additions & 6 deletions block.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,11 +430,12 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
}
}

/* call the change callback */
bs->media_changed = 1;
if (bs->change_cb)
bs->change_cb(bs->change_opaque);

if (!bdrv_key_required(bs)) {
/* call the change callback */
bs->media_changed = 1;
if (bs->change_cb)
bs->change_cb(bs->change_opaque);
}
return 0;
}

Expand Down Expand Up @@ -989,7 +990,15 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)
return -1;
ret = bs->drv->bdrv_set_key(bs, key);
bs->valid_key = (ret == 0);
if (ret < 0) {
bs->valid_key = 0;
} else if (!bs->valid_key) {
bs->valid_key = 1;
/* call the change callback now, we skipped it on open */
bs->media_changed = 1;
if (bs->change_cb)
bs->change_cb(bs->change_opaque);
}
return ret;
}

Expand Down
6 changes: 5 additions & 1 deletion console.h
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,11 @@ void term_flush(void);
void term_print_help(void);
void monitor_suspend(void);
void monitor_resume(void);
int monitor_read_bdrv_key(BlockDriverState *bs);

#include "block.h"
void monitor_read_bdrv_key_start(BlockDriverState *bs,
BlockDriverCompletionFunc *completion_cb,
void *opaque);

/* readline.c */
typedef void ReadLineFunc(void *opaque, const char *str);
Expand Down
10 changes: 8 additions & 2 deletions hw/usb-msd.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ static void usb_msd_handle_destroy(USBDevice *dev)
qemu_free(s);
}

USBDevice *usb_msd_init(const char *filename, BlockDriverState **pbs)
USBDevice *usb_msd_init(const char *filename)
{
MSDState *s;
BlockDriverState *bdrv;
Expand Down Expand Up @@ -554,7 +554,6 @@ USBDevice *usb_msd_init(const char *filename, BlockDriverState **pbs)
if (bdrv_open2(bdrv, filename, 0, drv) < 0)
goto fail;
s->bs = bdrv;
*pbs = bdrv;

s->dev.speed = USB_SPEED_FULL;
s->dev.handle_packet = usb_generic_handle_packet;
Expand All @@ -574,3 +573,10 @@ USBDevice *usb_msd_init(const char *filename, BlockDriverState **pbs)
qemu_free(s);
return NULL;
}

BlockDriverState *usb_msd_get_bdrv(USBDevice *dev)
{
MSDState *s = (MSDState *)dev;

return s->bs;
}
3 changes: 2 additions & 1 deletion hw/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,8 @@ USBDevice *usb_keyboard_init(void);
void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *));

/* usb-msd.c */
USBDevice *usb_msd_init(const char *filename, BlockDriverState **pbs);
USBDevice *usb_msd_init(const char *filename);
BlockDriverState *usb_msd_get_bdrv(USBDevice *dev);

/* usb-net.c */
USBDevice *usb_net_init(NICInfo *nd);
Expand Down
114 changes: 63 additions & 51 deletions monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,18 @@ static const term_cmd_t info_cmds[];

static uint8_t term_outbuf[1024];
static int term_outbuf_index;
static BlockDriverCompletionFunc *password_completion_cb;
static void *password_opaque;

static void monitor_start_input(void);
static void monitor_readline(const char *prompt, int is_password,
char *buf, int buf_size);

static CPUState *mon_cpu = NULL;

static void monitor_read_password(ReadLineFunc *readline_func, void *opaque)
{
readline_start("Password: ", 1, readline_func, opaque);
}

void term_flush(void)
{
int i;
Expand Down Expand Up @@ -435,21 +440,29 @@ static void do_change_block(const char *device, const char *filename, const char
if (eject_device(bs, 0) < 0)
return;
bdrv_open2(bs, filename, 0, drv);
monitor_read_bdrv_key(bs);
monitor_read_bdrv_key_start(bs, NULL, NULL);
}

static void change_vnc_password_cb(void *opaque, const char *password)
{
if (vnc_display_password(NULL, password) < 0)
term_printf("could not set VNC server password\n");

monitor_start_input();
}

static void do_change_vnc(const char *target, const char *arg)
{
if (strcmp(target, "passwd") == 0 ||
strcmp(target, "password") == 0) {
char password[9];
if (arg) {
char password[9];
strncpy(password, arg, sizeof(password));
password[sizeof(password) - 1] = '\0';
} else
monitor_readline("Password: ", 1, password, sizeof(password));
if (vnc_display_password(NULL, password) < 0)
term_printf("could not set VNC server password\n");
change_vnc_password_cb(NULL, password);
} else {
monitor_read_password(change_vnc_password_cb, NULL);
}
} else {
if (vnc_display_open(NULL, target) < 0)
term_printf("could not start VNC server on %s\n", target);
Expand Down Expand Up @@ -496,15 +509,7 @@ static void do_stop(void)
vm_stop(EXCP_INTERRUPT);
}

static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
{
int *err = opaque;

if (bdrv_key_required(bs))
*err = monitor_read_bdrv_key(bs);
else
*err = 0;
}
static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs);

static void do_cont(void)
{
Expand All @@ -516,6 +521,23 @@ static void do_cont(void)
vm_start();
}

static void bdrv_key_cb(void *opaque, int err)
{
/* another key was set successfully, retry to continue */
if (!err)
do_cont();
}

static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
{
int *err = opaque;

if (!*err && bdrv_key_required(bs)) {
*err = -EBUSY;
monitor_read_bdrv_key_start(bs, bdrv_key_cb, NULL);
}
}

#ifdef CONFIG_GDBSTUB
static void do_gdbserver(const char *port)
{
Expand Down Expand Up @@ -2835,7 +2857,7 @@ static void monitor_handle_command1(void *opaque, const char *cmdline)
{
monitor_handle_command(cmdline);
if (!monitor_suspended)
monitor_start_input();
readline_show_prompt();
else
monitor_suspended = 2;
}
Expand Down Expand Up @@ -2898,46 +2920,36 @@ void monitor_init(CharDriverState *hd, int show_banner)
readline_start("", 0, monitor_handle_command1, NULL);
}

/* XXX: use threads ? */
/* modal monitor readline */
static int monitor_readline_started;
static char *monitor_readline_buf;
static int monitor_readline_buf_size;

static void monitor_readline_cb(void *opaque, const char *input)
static void bdrv_password_cb(void *opaque, const char *password)
{
pstrcpy(monitor_readline_buf, monitor_readline_buf_size, input);
monitor_readline_started = 0;
}
BlockDriverState *bs = opaque;
int ret = 0;

static void monitor_readline(const char *prompt, int is_password,
char *buf, int buf_size)
{
readline_start(prompt, is_password, monitor_readline_cb, NULL);
readline_show_prompt();
monitor_readline_buf = buf;
monitor_readline_buf_size = buf_size;
monitor_readline_started = 1;
while (monitor_readline_started) {
main_loop_wait(10);
if (bdrv_set_key(bs, password) != 0) {
term_printf("invalid password\n");
ret = -EPERM;
}
if (password_completion_cb)
password_completion_cb(password_opaque, ret);

monitor_start_input();
}

int monitor_read_bdrv_key(BlockDriverState *bs)
void monitor_read_bdrv_key_start(BlockDriverState *bs,
BlockDriverCompletionFunc *completion_cb,
void *opaque)
{
char password[256];
int i;

if (!bdrv_is_encrypted(bs))
return 0;
if (!bdrv_key_required(bs)) {
if (completion_cb)
completion_cb(opaque, 0);
return;
}

term_printf("%s (%s) is encrypted.\n", bdrv_get_device_name(bs),
bdrv_get_encrypted_filename(bs));
for(i = 0; i < 3; i++) {
monitor_readline("Password: ", 1, password, sizeof(password));
if (bdrv_set_key(bs, password) == 0)
return 0;
term_printf("invalid password\n");
}
return -EPERM;

password_completion_cb = completion_cb;
password_opaque = opaque;

monitor_read_password(bdrv_password_cb, bs);
}
19 changes: 15 additions & 4 deletions vl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2661,6 +2661,16 @@ int usb_device_add_dev(USBDevice *dev)
return 0;
}

static void usb_msd_password_cb(void *opaque, int err)
{
USBDevice *dev = opaque;

if (!err)
usb_device_add_dev(dev);
else
dev->handle_destroy(dev);
}

static int usb_device_add(const char *devname, int is_hotplug)
{
const char *p;
Expand All @@ -2680,14 +2690,15 @@ static int usb_device_add(const char *devname, int is_hotplug)
} else if (strstart(devname, "disk:", &p)) {
BlockDriverState *bs;

dev = usb_msd_init(p, &bs);
dev = usb_msd_init(p);
if (!dev)
return -1;
bs = usb_msd_get_bdrv(dev);
if (bdrv_key_required(bs)) {
autostart = 0;
if (is_hotplug && monitor_read_bdrv_key(bs) < 0) {
dev->handle_destroy(dev);
return -1;
if (is_hotplug) {
monitor_read_bdrv_key_start(bs, usb_msd_password_cb, dev);
return 0;
}
}
} else if (!strcmp(devname, "wacom-tablet")) {
Expand Down

0 comments on commit bb5fc20

Please sign in to comment.