[libvirt] Improve the reliability of pty path parsing

The following are improve the reliability of libvirt's mapping of character devices to pty paths. When qemu starts up it will output one or more lines of the form: char device redirected to /dev/pts/5 Note that the character device this refers to is not indicated, so the only way to match this up is by knowing the order they're written in. This is not a well-defined interface, and is therefore voodoo-magic. The current code works against current versions of QEMU. However, when using the -chardev syntax of newer QEMU, the output order changes (putting chardev first). The first patch works by making all character devices use -chardev if it's available. As well as being a better syntax, this makes the output of the redirection lines again match the order they're specified on the command line. The second patch uses this ordering to parse the ptys for channel devices from the log output. The third patch (almost) obsoletes the log output parsing method. If QEMU's monitor supports 'info chardev', this gives structured information about character devices, including pty mappings. The log output parsing method is still required because QEMU may not support info chardev, and because the monitor itself can be on a pty. The danger of the third patch is that it will fix errors in the log output parsing code, which may then bitrot. Matt

Change -monitor, -serial and -parallel output to use -chardev if it is available. * src/qemu/qemu_conf.c: Update qemudBuildCommandLine to use -chardev where available. * tests/qemuxml2argvtest.c tests/qemuxml2argvdata/: Add -chardev equivalents for all current serial and parallel tests. --- src/qemu/qemu_conf.c | 93 ++++++++++++++++--- .../qemuxml2argv-channel-guestfwd.args | 2 +- .../qemuxml2argv-console-compat-chardev.args | 1 + .../qemuxml2argv-console-compat-chardev.xml | 28 ++++++ .../qemuxml2argv-parallel-tcp-chardev.args | 1 + .../qemuxml2argv-parallel-tcp-chardev.xml | 27 ++++++ .../qemuxml2argv-serial-dev-chardev.args | 1 + .../qemuxml2argv-serial-dev-chardev.xml | 30 ++++++ .../qemuxml2argv-serial-file-chardev.args | 1 + .../qemuxml2argv-serial-file-chardev.xml | 30 ++++++ .../qemuxml2argv-serial-many-chardev.args | 1 + .../qemuxml2argv-serial-many-chardev.xml | 32 +++++++ .../qemuxml2argv-serial-pty-chardev.args | 1 + .../qemuxml2argv-serial-pty-chardev.xml | 28 ++++++ .../qemuxml2argv-serial-tcp-chardev.args | 1 + .../qemuxml2argv-serial-tcp-chardev.xml | 32 +++++++ .../qemuxml2argv-serial-tcp-telnet-chardev.args | 1 + .../qemuxml2argv-serial-tcp-telnet-chardev.xml | 32 +++++++ .../qemuxml2argv-serial-udp-chardev.args | 1 + .../qemuxml2argv-serial-udp-chardev.xml | 32 +++++++ .../qemuxml2argv-serial-unix-chardev.args | 1 + .../qemuxml2argv-serial-unix-chardev.xml | 30 ++++++ .../qemuxml2argv-serial-vc-chardev.args | 1 + .../qemuxml2argv-serial-vc-chardev.xml | 28 ++++++ tests/qemuxml2argvtest.c | 12 +++ 25 files changed, 431 insertions(+), 16 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-console-compat-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-console-compat-chardev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp-chardev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-dev-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-dev-chardev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-file-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-file-chardev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-many-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-many-chardev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-pty-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-pty-chardev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-chardev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet-chardev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-udp-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-udp-chardev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-unix-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-unix-chardev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-vc-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-vc-chardev.xml diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index f26e94d..51d8515 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1858,12 +1858,27 @@ int qemudBuildCommandLine(virConnectPtr conn, if (monitor_chr) { virBuffer buf = VIR_BUFFER_INITIALIZER; - qemudBuildCommandLineChrDevStr(monitor_chr, &buf); - if (virBufferError(&buf)) - goto error; + /* Use -chardev if it's available */ + if (qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) { + qemudBuildCommandLineChrDevChardevStr(monitor_chr, "monitor", &buf); + if (virBufferError(&buf)) + goto error; + + ADD_ARG_LIT("-chardev"); + ADD_ARG(virBufferContentAndReset(&buf)); + + ADD_ARG_LIT("-monitor"); + ADD_ARG_LIT("chardev:monitor"); + } + + else { + qemudBuildCommandLineChrDevStr(monitor_chr, &buf); + if (virBufferError(&buf)) + goto error; - ADD_ARG_LIT("-monitor"); - ADD_ARG(virBufferContentAndReset(&buf)); + ADD_ARG_LIT("-monitor"); + ADD_ARG(virBufferContentAndReset(&buf)); + } } if (def->localtime) @@ -2146,12 +2161,36 @@ int qemudBuildCommandLine(virConnectPtr conn, virBuffer buf = VIR_BUFFER_INITIALIZER; virDomainChrDefPtr serial = def->serials[i]; - qemudBuildCommandLineChrDevStr(serial, &buf); - if (virBufferError(&buf)) - goto error; + /* Use -chardev if it's available */ + if (qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) { + char id[16]; - ADD_ARG_LIT("-serial"); - ADD_ARG(virBufferContentAndReset(&buf)); + if (snprintf(id, sizeof(id), "serial%i", i) > sizeof(id)) + goto error; + + qemudBuildCommandLineChrDevChardevStr(serial, id, &buf); + if (virBufferError(&buf)) + goto error; + + ADD_ARG_LIT("-chardev"); + ADD_ARG(virBufferContentAndReset(&buf)); + + virBufferVSprintf(&buf, "chardev:%s", id); + if (virBufferError(&buf)) + goto error; + + ADD_ARG_LIT("-serial"); + ADD_ARG(virBufferContentAndReset(&buf)); + } + + else { + qemudBuildCommandLineChrDevStr(serial, &buf); + if (virBufferError(&buf)) + goto error; + + ADD_ARG_LIT("-serial"); + ADD_ARG(virBufferContentAndReset(&buf)); + } } } @@ -2163,12 +2202,36 @@ int qemudBuildCommandLine(virConnectPtr conn, virBuffer buf = VIR_BUFFER_INITIALIZER; virDomainChrDefPtr parallel = def->parallels[i]; - qemudBuildCommandLineChrDevStr(parallel, &buf); - if (virBufferError(&buf)) - goto error; + /* Use -chardev if it's available */ + if (qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) { + char id[16]; - ADD_ARG_LIT("-parallel"); - ADD_ARG(virBufferContentAndReset(&buf)); + if (snprintf(id, sizeof(id), "parallel%i", i) > sizeof(id)) + goto error; + + qemudBuildCommandLineChrDevChardevStr(parallel, id, &buf); + if (virBufferError(&buf)) + goto error; + + ADD_ARG_LIT("-chardev"); + ADD_ARG(virBufferContentAndReset(&buf)); + + virBufferVSprintf(&buf, "chardev:%s", id); + if (virBufferError(&buf)) + goto error; + + ADD_ARG_LIT("-parallel"); + ADD_ARG(virBufferContentAndReset(&buf)); + } + + else { + qemudBuildCommandLineChrDevStr(parallel, &buf); + if (virBufferError(&buf)) + goto error; + + ADD_ARG_LIT("-parallel"); + ADD_ARG(virBufferContentAndReset(&buf)); + } } } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-channel-guestfwd.args b/tests/qemuxml2argvdata/qemuxml2argv-channel-guestfwd.args index b5bb46d..f3b0c30 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-channel-guestfwd.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-guestfwd.args @@ -1 +1 @@ -LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -chardev pipe,id=channel0,path=/tmp/guestfwd -net user,guestfwd=tcp:10.0.2.1:4600-chardev:channel0 -usb +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -chardev socket,id=monitor0,path=/tmp/test-monitor,server,nowait -monitor chardev:monitor0 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -chardev pipe,id=channel0,path=/tmp/guestfwd -net user,guestfwd=tcp:10.0.2.1:4600-chardev:channel0 -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-console-compat-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-console-compat-chardev.args new file mode 100644 index 0000000..1237250 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-console-compat-chardev.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -chardev socket,id=monitor0,path=/tmp/test-monitor,server,nowait -monitor chardev:monitor0 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -chardev pty,id=serial0 -serial chardev:serial0 -parallel none -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-console-compat-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-console-compat-chardev.xml new file mode 100644 index 0000000..c16ae07 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-console-compat-chardev.xml @@ -0,0 +1,28 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <serial type='pty'> + <target port='0'/> + </serial> + <console type='pty'> + <target port='0'/> + </console> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp-chardev.args new file mode 100644 index 0000000..65783fb --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp-chardev.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -chardev socket,id=monitor0,path=/tmp/test-monitor,server,nowait -monitor chardev:monitor0 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -chardev socket,id=parallel0,host=127.0.0.1,port=9999,server,nowait -parallel chardev:parallel0 -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp-chardev.xml new file mode 100644 index 0000000..08176f1 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp-chardev.xml @@ -0,0 +1,27 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <parallel type='tcp'> + <source mode='bind' host='127.0.0.1' service='9999'/> + <protocol type='raw'/> + <target port='0'/> + </parallel> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-dev-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-dev-chardev.args new file mode 100644 index 0000000..7ecb3e8 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-dev-chardev.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -chardev socket,id=monitor0,path=/tmp/test-monitor,server,nowait -monitor chardev:monitor0 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -chardev tty,id=serial0,path=/dev/ttyS2 -serial chardev:serial0 -parallel none -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-dev-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-dev-chardev.xml new file mode 100644 index 0000000..2b8ef5a --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-dev-chardev.xml @@ -0,0 +1,30 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <serial type='dev'> + <source path='/dev/ttyS2'/> + <target port='0'/> + </serial> + <console type='dev'> + <source path='/dev/ttyS2'/> + <target port='0'/> + </console> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-file-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-file-chardev.args new file mode 100644 index 0000000..fd3cc4e --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-file-chardev.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -chardev socket,id=monitor0,path=/tmp/test-monitor,server,nowait -monitor chardev:monitor0 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -chardev file,id=serial0,path=/tmp/serial.log -serial chardev:serial0 -parallel none -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-file-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-file-chardev.xml new file mode 100644 index 0000000..3726816 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-file-chardev.xml @@ -0,0 +1,30 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <serial type='file'> + <source path='/tmp/serial.log'/> + <target port='0'/> + </serial> + <console type='file'> + <source path='/tmp/serial.log'/> + <target port='0'/> + </console> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-many-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-many-chardev.args new file mode 100644 index 0000000..46113fc --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-many-chardev.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -chardev socket,id=monitor0,path=/tmp/test-monitor,server,nowait -monitor chardev:monitor0 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -chardev pty,id=serial0 -serial chardev:serial0 -chardev file,id=serial1,path=/tmp/serial.log -serial chardev:serial1 -parallel none -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-many-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-many-chardev.xml new file mode 100644 index 0000000..444e85b --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-many-chardev.xml @@ -0,0 +1,32 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <serial type='pty'> + <target port='0'/> + </serial> + <serial type='file'> + <source path='/tmp/serial.log'/> + <target port='1'/> + </serial> + <console type='pty'> + <target port='0'/> + </console> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-pty-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-pty-chardev.args new file mode 100644 index 0000000..1237250 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-pty-chardev.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -chardev socket,id=monitor0,path=/tmp/test-monitor,server,nowait -monitor chardev:monitor0 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -chardev pty,id=serial0 -serial chardev:serial0 -parallel none -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-pty-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-pty-chardev.xml new file mode 100644 index 0000000..c16ae07 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-pty-chardev.xml @@ -0,0 +1,28 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <serial type='pty'> + <target port='0'/> + </serial> + <console type='pty'> + <target port='0'/> + </console> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-chardev.args new file mode 100644 index 0000000..6255103 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-chardev.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -chardev socket,id=monitor0,path=/tmp/test-monitor,server,nowait -monitor chardev:monitor0 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -chardev socket,id=serial0,host=127.0.0.1,port=9999 -serial chardev:serial0 -parallel none -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-chardev.xml new file mode 100644 index 0000000..3bcf62d --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-chardev.xml @@ -0,0 +1,32 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <serial type='tcp'> + <source mode='connect' host='127.0.0.1' service='9999'/> + <protocol type='raw'/> + <target port='0'/> + </serial> + <console type='tcp'> + <source mode='connect' host='127.0.0.1' service='9999'/> + <protocol type='raw'/> + <target port='0'/> + </console> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet-chardev.args new file mode 100644 index 0000000..c807e64 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet-chardev.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -chardev socket,id=monitor0,path=/tmp/test-monitor,server,nowait -monitor chardev:monitor0 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -chardev socket,id=serial0,host=127.0.0.1,port=9999,telnet,server,nowait -serial chardev:serial0 -parallel none -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet-chardev.xml new file mode 100644 index 0000000..bea4306 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet-chardev.xml @@ -0,0 +1,32 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <serial type='tcp'> + <source mode='bind' host='127.0.0.1' service='9999'/> + <protocol type='telnet'/> + <target port='0'/> + </serial> + <console type='tcp'> + <source mode='bind' host='127.0.0.1' service='9999'/> + <protocol type='telnet'/> + <target port='0'/> + </console> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-udp-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-udp-chardev.args new file mode 100644 index 0000000..088c461 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-udp-chardev.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -chardev socket,id=monitor0,path=/tmp/test-monitor,server,nowait -monitor chardev:monitor0 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -chardev udp,id=serial0,host=127.0.0.1,port=9998,localaddr=127.0.0.1,localport=9999 -serial chardev:serial0 -parallel none -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-udp-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-udp-chardev.xml new file mode 100644 index 0000000..115166d --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-udp-chardev.xml @@ -0,0 +1,32 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <serial type='udp'> + <source mode='bind' host='127.0.0.1' service='9999'/> + <source mode='connect' host='127.0.0.1' service='9998'/> + <target port='0'/> + </serial> + <console type='udp'> + <source mode='bind' host='127.0.0.1' service='9999'/> + <source mode='connect' host='127.0.0.1' service='9998'/> + <target port='0'/> + </console> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-unix-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-unix-chardev.args new file mode 100644 index 0000000..92a7efc --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-unix-chardev.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -chardev socket,id=monitor0,path=/tmp/test-monitor,server,nowait -monitor chardev:monitor0 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -chardev socket,id=serial0,path=/tmp/serial.sock -serial chardev:serial0 -parallel none -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-unix-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-unix-chardev.xml new file mode 100644 index 0000000..4236b4c --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-unix-chardev.xml @@ -0,0 +1,30 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <serial type='unix'> + <source mode='connect' path='/tmp/serial.sock'/> + <target port='0'/> + </serial> + <console type='unix'> + <source mode='connect' path='/tmp/serial.sock'/> + <target port='0'/> + </console> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-vc-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-vc-chardev.args new file mode 100644 index 0000000..c427c0e --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-vc-chardev.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -chardev socket,id=monitor0,path=/tmp/test-monitor,server,nowait -monitor chardev:monitor0 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -chardev vc,id=serial0 -serial chardev:serial0 -parallel none -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-vc-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-vc-chardev.xml new file mode 100644 index 0000000..1e5de8f --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-vc-chardev.xml @@ -0,0 +1,28 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <serial type='vc'> + <target port='0'/> + </serial> + <console type='vc'> + <target port='0'/> + </console> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index c948379..da6b761 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -269,6 +269,18 @@ mymain(int argc, char **argv) DO_TEST("parallel-tcp", 0); DO_TEST("console-compat", 0); + DO_TEST("serial-vc-chardev", QEMUD_CMD_FLAG_CHARDEV); + DO_TEST("serial-pty-chardev", QEMUD_CMD_FLAG_CHARDEV); + DO_TEST("serial-dev-chardev", QEMUD_CMD_FLAG_CHARDEV); + DO_TEST("serial-file-chardev", QEMUD_CMD_FLAG_CHARDEV); + DO_TEST("serial-unix-chardev", QEMUD_CMD_FLAG_CHARDEV); + DO_TEST("serial-tcp-chardev", QEMUD_CMD_FLAG_CHARDEV); + DO_TEST("serial-udp-chardev", QEMUD_CMD_FLAG_CHARDEV); + DO_TEST("serial-tcp-telnet-chardev", QEMUD_CMD_FLAG_CHARDEV); + DO_TEST("serial-many-chardev", QEMUD_CMD_FLAG_CHARDEV); + DO_TEST("parallel-tcp-chardev", QEMUD_CMD_FLAG_CHARDEV); + DO_TEST("console-compat-chardev", QEMUD_CMD_FLAG_CHARDEV); + DO_TEST("channel-guestfwd", QEMUD_CMD_FLAG_CHARDEV); DO_TEST("sound", 0); -- 1.6.5.2

On Mon, Nov 23, 2009 at 12:30:27PM +0000, Matthew Booth wrote:
Change -monitor, -serial and -parallel output to use -chardev if it is available.
* src/qemu/qemu_conf.c: Update qemudBuildCommandLine to use -chardev where available. * tests/qemuxml2argvtest.c tests/qemuxml2argvdata/: Add -chardev equivalents for all current serial and parallel tests.
ACK Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

* src/qemu/qemu_driver.c: Parse pty devices for channels --- src/qemu/qemu_driver.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2c5086b..ebf44b0 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1271,6 +1271,16 @@ qemudFindCharDevicePTYs(virConnectPtr conn, } } + /* then the channel devices */ + for (i = 0 ; i < vm->def->nchannels ; i++) { + virDomainChrDefPtr chr = vm->def->channels[i]; + if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) { + if ((ret = qemudExtractTTYPath(conn, output, &offset, + &chr->data.file.path)) != 0) + return ret; + } + } + return 0; } -- 1.6.5.2

On Mon, Nov 23, 2009 at 12:30:28PM +0000, Matthew Booth wrote:
* src/qemu/qemu_driver.c: Parse pty devices for channels --- src/qemu/qemu_driver.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2c5086b..ebf44b0 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1271,6 +1271,16 @@ qemudFindCharDevicePTYs(virConnectPtr conn, } }
+ /* then the channel devices */ + for (i = 0 ; i < vm->def->nchannels ; i++) { + virDomainChrDefPtr chr = vm->def->channels[i]; + if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) { + if ((ret = qemudExtractTTYPath(conn, output, &offset, + &chr->data.file.path)) != 0) + return ret; + } + } + return 0; }
--
ACK, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

This change makes the QEMU driver get pty paths from the output of the monitor 'info chardev' command. This output is structured, and contains both the name of the device and the path on the same line. This is considerably more reliable than parsing the startup log output, which requires the parsing code to know which order QEMU will print pty information in. Note that we still need to parse the log output as the monitor itself may be on a pty. This should be rare, however, and the new code will replace all pty paths parsed by the log output method once the monitor is available. * src/qemu/qemu_monitor.(c|h) src/qemu_monitor_text.(c|h): Implement qemuMonitorGetPtyPaths(). * src/qemu/qemu_driver.c: Get pty path information using qemuMonitorGetPtyPaths(). --- src/qemu/qemu_driver.c | 68 +++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_monitor.c | 9 +++++ src/qemu/qemu_monitor.h | 3 ++ src/qemu/qemu_monitor_text.c | 71 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 ++ 5 files changed, 153 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ebf44b0..90dd9cd 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1239,6 +1239,40 @@ qemudExtractTTYPath(virConnectPtr conn, } static int +qemudFindCharDevicePTYsMonitor(virConnectPtr conn, + virDomainObjPtr vm, + virHashTablePtr paths) +{ + int i; + +#define LOOKUP_PTYS(array, arraylen, idprefix) \ + for (i = 0 ; i < (arraylen) ; i++) { \ + virDomainChrDefPtr chr = (array)[i]; \ + if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) { \ + char id[16]; \ +\ + if (snprintf(id, sizeof(id), idprefix "%i", i) >= sizeof(id)) \ + return -1; \ +\ + const char *path = (const char *) virHashLookup(paths, id); \ + if (path == NULL) { \ + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, \ + _("no assigned pty for device %s"), id); \ + return -1; \ + } \ +\ + chr->data.file.path = strdup(path); \ + } \ + } + + LOOKUP_PTYS(vm->def->serials, vm->def->nserials, "serial"); + LOOKUP_PTYS(vm->def->parallels, vm->def->nparallels, "parallel"); + LOOKUP_PTYS(vm->def->channels, vm->def->nchannels, "channel"); + + return 0; +} + +static int qemudFindCharDevicePTYs(virConnectPtr conn, virDomainObjPtr vm, const char *output, @@ -1284,6 +1318,11 @@ qemudFindCharDevicePTYs(virConnectPtr conn, return 0; } +static void qemudFreePtyPath(void *payload, const char *name ATTRIBUTE_UNUSED) +{ + free(payload); +} + static int qemudWaitForMonitor(virConnectPtr conn, struct qemud_driver* driver, @@ -1291,7 +1330,7 @@ qemudWaitForMonitor(virConnectPtr conn, { char buf[4096]; /* Plenty of space to get startup greeting */ int logfd; - int ret; + int ret = -1; if ((logfd = qemudLogReadFD(conn, driver->logDir, vm->def->name, pos)) < 0) @@ -1317,7 +1356,32 @@ qemudWaitForMonitor(virConnectPtr conn, if (qemuConnectMonitor(vm) < 0) return -1; - return 0; + /* Try to get the pty path mappings again via the monitor. This is much more + * reliable if it's available. + * Note that the monitor itself can be on a pty, so we still need to try the + * log output method. */ + virHashTablePtr paths = virHashCreate(0); + if (paths == NULL) { + virReportOOMError(NULL); + goto cleanup; + } + + qemuDomainObjEnterMonitor(vm); + qemuDomainObjPrivatePtr priv = vm->privateData; + ret = qemuMonitorGetPtyPaths(priv->mon, paths); + qemuDomainObjExitMonitor(vm); + + VIR_DEBUG("qemuMonitorGetPtyPaths returned %i", ret); + if (ret == 0) { + ret = qemudFindCharDevicePTYsMonitor(conn, vm, paths); + } + +cleanup: + if (paths) { + virHashFree(paths, qemudFreePtyPath); + } + + return ret; } static int diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index f0ef81b..92f005a 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -904,3 +904,12 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon, return qemuMonitorTextRemoveHostNetwork(mon, vlan, netname); } + +int qemuMonitorGetPtyPaths(qemuMonitorPtr mon, + virHashTablePtr paths) +{ + DEBUG("mon=%p, fd=%d", + mon, mon->fd); + + return qemuMonitorTextGetPtyPaths(mon, paths); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 71688cb..dc14bbe 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -28,6 +28,7 @@ #include "internal.h" #include "domain_conf.h" +#include "hash.h" typedef struct _qemuMonitor qemuMonitor; typedef qemuMonitor *qemuMonitorPtr; @@ -244,5 +245,7 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon, int vlan, const char *netname); +int qemuMonitorGetPtyPaths(qemuMonitorPtr mon, + virHashTablePtr paths); #endif /* QEMU_MONITOR_H */ diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index d39a417..21ab957 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1648,3 +1648,74 @@ cleanup: VIR_FREE(reply); return ret; } + + +/* Parse the output of "info chardev" and return a hash of pty paths. + * + * Output is: + * foo: filename=pty:/dev/pts/7 + * monitor: filename=stdio + * serial0: filename=vc + * parallel0: filename=vc + * + * Non-pty lines are ignored. In the above example, key is 'foo', value is + * '/dev/pty/7'. The hash will contain only a single value. + */ + +int qemuMonitorTextGetPtyPaths(qemuMonitorPtr mon, + virHashTablePtr paths) +{ + const char *cmd = "info chardev"; + char *reply = NULL; + int ret = -1; + + if (qemuMonitorCommand(mon, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("failed to retrieve chardev info in qemu with '%s'"), + cmd); + goto cleanup; + } + + char *pos = reply; /* The current start of searching */ + char *end = pos + strlen(reply); /* The end of the reply string */ + char *eol; /* The character which ends the current line */ + + while (pos < end) { + /* Split the output into lines */ + eol = memchr(pos, '\n', end - pos); + if (eol == NULL) + eol = end; + + /* Look for 'filename=pty:' */ +#define NEEDLE "filename=pty:" + char *needle = memmem(pos, eol - pos, NEEDLE, strlen(NEEDLE)); + + /* If it's not there we can ignore this line */ + if (!needle) + goto next; + + /* id is everthing from the beginning of the line to the ':' + * find ':' and turn it into a terminator */ + char *colon = memchr(pos, ':', needle - pos); + if (colon == NULL) + goto next; + *colon = '\0'; + char *id = pos; + + /* Path is everything after needle to the end of the line */ + *eol = '\0'; + char *path = needle + strlen(NEEDLE); + + virHashAddEntry(paths, id, strdup(path)); +#undef NEEDLE + + next: + pos = eol + 1; + } + + ret = 0; + +cleanup: + VIR_FREE(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 6bca07a..d42c443 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -28,6 +28,7 @@ #include "internal.h" #include "qemu_monitor.h" +#include "hash.h" int qemuMonitorTextIOProcess(qemuMonitorPtr mon, const char *data, @@ -152,4 +153,7 @@ int qemuMonitorTextRemoveHostNetwork(qemuMonitorPtr mon, int vlan, const char *netname); +int qemuMonitorTextGetPtyPaths(qemuMonitorPtr mon, + virHashTablePtr paths); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.5.2

On Mon, Nov 23, 2009 at 12:30:29PM +0000, Matthew Booth wrote:
This change makes the QEMU driver get pty paths from the output of the monitor 'info chardev' command. This output is structured, and contains both the name of the device and the path on the same line. This is considerably more reliable than parsing the startup log output, which requires the parsing code to know which order QEMU will print pty information in.
Note that we still need to parse the log output as the monitor itself may be on a pty. This should be rare, however, and the new code will replace all pty paths parsed by the log output method once the monitor is available.
* src/qemu/qemu_monitor.(c|h) src/qemu_monitor_text.(c|h): Implement qemuMonitorGetPtyPaths(). * src/qemu/qemu_driver.c: Get pty path information using qemuMonitorGetPtyPaths(). --- src/qemu/qemu_driver.c | 68 +++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_monitor.c | 9 +++++ src/qemu/qemu_monitor.h | 3 ++ src/qemu/qemu_monitor_text.c | 71 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 ++ 5 files changed, 153 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ebf44b0..90dd9cd 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1239,6 +1239,40 @@ qemudExtractTTYPath(virConnectPtr conn, }
static int +qemudFindCharDevicePTYsMonitor(virConnectPtr conn, + virDomainObjPtr vm, + virHashTablePtr paths) +{ + int i; + +#define LOOKUP_PTYS(array, arraylen, idprefix) \ + for (i = 0 ; i < (arraylen) ; i++) { \ + virDomainChrDefPtr chr = (array)[i]; \ + if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) { \ + char id[16]; \ +\ + if (snprintf(id, sizeof(id), idprefix "%i", i) >= sizeof(id)) \ + return -1; \ +\ + const char *path = (const char *) virHashLookup(paths, id); \ + if (path == NULL) { \ + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, \ + _("no assigned pty for device %s"), id); \ + return -1; \ + } \ +\ + chr->data.file.path = strdup(path); \ + } \ + }
Can you indent the \ to they all line up in the right hand side.
+ + LOOKUP_PTYS(vm->def->serials, vm->def->nserials, "serial"); + LOOKUP_PTYS(vm->def->parallels, vm->def->nparallels, "parallel"); + LOOKUP_PTYS(vm->def->channels, vm->def->nchannels, "channel"); +
#undef LOOKUP_PTYS
+ return 0; +} + +static int qemudFindCharDevicePTYs(virConnectPtr conn, virDomainObjPtr vm, const char *output, @@ -1284,6 +1318,11 @@ qemudFindCharDevicePTYs(virConnectPtr conn, return 0; }
+static void qemudFreePtyPath(void *payload, const char *name ATTRIBUTE_UNUSED) +{ + free(payload);
VIR_FREE
+} + static int qemudWaitForMonitor(virConnectPtr conn, struct qemud_driver* driver, @@ -1291,7 +1330,7 @@ qemudWaitForMonitor(virConnectPtr conn, { char buf[4096]; /* Plenty of space to get startup greeting */ int logfd; - int ret; + int ret = -1;
if ((logfd = qemudLogReadFD(conn, driver->logDir, vm->def->name, pos)) < 0) @@ -1317,7 +1356,32 @@ qemudWaitForMonitor(virConnectPtr conn, if (qemuConnectMonitor(vm) < 0) return -1;
- return 0; + /* Try to get the pty path mappings again via the monitor. This is much more + * reliable if it's available. + * Note that the monitor itself can be on a pty, so we still need to try the + * log output method. */ + virHashTablePtr paths = virHashCreate(0); + if (paths == NULL) { + virReportOOMError(NULL); + goto cleanup; + } + + qemuDomainObjEnterMonitor(vm);
This needs to be EnterMonitorWithDriver(driver, vm), since the 'driver' is locked in this context
+ qemuDomainObjPrivatePtr priv = vm->privateData; + ret = qemuMonitorGetPtyPaths(priv->mon, paths); + qemuDomainObjExitMonitor(vm);
And ExitMonitorWithDriver
+ + VIR_DEBUG("qemuMonitorGetPtyPaths returned %i", ret); + if (ret == 0) { + ret = qemudFindCharDevicePTYsMonitor(conn, vm, paths); + } + +cleanup: + if (paths) { + virHashFree(paths, qemudFreePtyPath); + } + + return ret; }
+ + +/* Parse the output of "info chardev" and return a hash of pty paths. + * + * Output is: + * foo: filename=pty:/dev/pts/7 + * monitor: filename=stdio + * serial0: filename=vc + * parallel0: filename=vc + * + * Non-pty lines are ignored. In the above example, key is 'foo', value is + * '/dev/pty/7'. The hash will contain only a single value. + */ + +int qemuMonitorTextGetPtyPaths(qemuMonitorPtr mon, + virHashTablePtr paths) +{ + const char *cmd = "info chardev"; + char *reply = NULL; + int ret = -1; + + if (qemuMonitorCommand(mon, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("failed to retrieve chardev info in qemu with '%s'"), + cmd); + goto cleanup; + } + + char *pos = reply; /* The current start of searching */ + char *end = pos + strlen(reply); /* The end of the reply string */ + char *eol; /* The character which ends the current line */ + + while (pos < end) { + /* Split the output into lines */ + eol = memchr(pos, '\n', end - pos); + if (eol == NULL) + eol = end; + + /* Look for 'filename=pty:' */ +#define NEEDLE "filename=pty:" + char *needle = memmem(pos, eol - pos, NEEDLE, strlen(NEEDLE)); + + /* If it's not there we can ignore this line */ + if (!needle) + goto next; + + /* id is everthing from the beginning of the line to the ':' + * find ':' and turn it into a terminator */ + char *colon = memchr(pos, ':', needle - pos); + if (colon == NULL) + goto next; + *colon = '\0'; + char *id = pos; + + /* Path is everything after needle to the end of the line */ + *eol = '\0'; + char *path = needle + strlen(NEEDLE); + + virHashAddEntry(paths, id, strdup(path));
Not checking OOM on strdup() here, or for failure of virHashAddEntry()
+#undef NEEDLE + + next: + pos = eol + 1; + } + + ret = 0; + +cleanup: + VIR_FREE(reply); + return ret; +}
Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Wed, Nov 25, 2009 at 11:31:37AM +0000, Daniel P. Berrange wrote:
On Mon, Nov 23, 2009 at 12:30:29PM +0000, Matthew Booth wrote:
@@ -1291,7 +1330,7 @@ qemudWaitForMonitor(virConnectPtr conn, { char buf[4096]; /* Plenty of space to get startup greeting */ int logfd; - int ret; + int ret = -1;
if ((logfd = qemudLogReadFD(conn, driver->logDir, vm->def->name, pos)) < 0) @@ -1317,7 +1356,32 @@ qemudWaitForMonitor(virConnectPtr conn, if (qemuConnectMonitor(vm) < 0) return -1;
- return 0; + /* Try to get the pty path mappings again via the monitor. This is much more + * reliable if it's available. + * Note that the monitor itself can be on a pty, so we still need to try the + * log output method. */ + virHashTablePtr paths = virHashCreate(0); + if (paths == NULL) { + virReportOOMError(NULL); + goto cleanup; + } + + qemuDomainObjEnterMonitor(vm);
This needs to be EnterMonitorWithDriver(driver, vm), since the 'driver' is locked in this context
+ qemuDomainObjPrivatePtr priv = vm->privateData; + ret = qemuMonitorGetPtyPaths(priv->mon, paths); + qemuDomainObjExitMonitor(vm);
And ExitMonitorWithDriver
Loooks serious and was missing fro last patch so I made the change
+ /* Path is everything after needle to the end of the line */ + *eol = '\0'; + char *path = needle + strlen(NEEDLE); + + virHashAddEntry(paths, id, strdup(path));
Not checking OOM on strdup() here, or for failure of virHashAddEntry()
I fixed that too, I pushed the attached patch to clean those 2 issues, please check :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/
participants (3)
-
Daniel P. Berrange
-
Daniel Veillard
-
Matthew Booth