Markus Armbruster <armbru@xxxxxxxxxx> writes: > The __linux__ version of qemu_chr_open_pp_fd() tries to claim the > parport device with a PPCLAIM ioctl(). On success, it stores the file > descriptor in the chardev object, and returns success. On failure, it > closes the file descriptor, and returns failure. > > chardev_new() then passes the Chardev to object_unref(). This duly > calls char_parallel_finalize(), which closes the file descriptor > stored in the chardev object. Since qemu_chr_open_pp_fd() didn't > store it, it's still zero, so this closes standard input. Ooopsie. > > To demonstate, add a unit test. With the bug above unfixed, running > this test closes standard input. char_hotswap_test() happens to run > next. It opens a socket, duly gets file descriptor 0, and since it > tests for success with > 0 instead of >= 0, it fails. > > The test needs to be conditional exactly like the chardev it tests. > Since the condition is rather complicated, steal the solution from the > serial chardev: define HAVE_CHARDEV_PARALLEL in qemu/osdep.h. This > also permits simplifying chardev/meson.build a bit. > > The bug fix is easy enough: store the file descriptor, and leave > closing it to char_parallel_finalize(). > > Signed-off-by: Markus Armbruster <armbru@xxxxxxxxxx> [...] > diff --git a/chardev/char-parallel.c b/chardev/char-parallel.c > index a5164f975a..78697d7522 100644 > --- a/chardev/char-parallel.c > +++ b/chardev/char-parallel.c > @@ -164,13 +164,13 @@ static void qemu_chr_open_pp_fd(Chardev *chr, > { > ParallelChardev *drv = PARALLEL_CHARDEV(chr); > > + drv->fd = fd; > + > if (ioctl(fd, PPCLAIM) < 0) { > error_setg_errno(errp, errno, "not a parallel port"); > - close(fd); > return; > } > > - drv->fd = fd; > drv->mode = IEEE1284_MODE_COMPAT; > } > #endif /* __linux__ */ > @@ -238,6 +238,7 @@ static void qemu_chr_open_pp_fd(Chardev *chr, > } > #endif > > +#ifdef HAVE_CHARDEV_PARALLEL > static void qmp_chardev_open_parallel(Chardev *chr, > ChardevBackend *backend, > bool *be_opened, > @@ -306,3 +307,5 @@ static void register_types(void) > } > > type_init(register_types); > + > +#endif /* HAVE_CHARDEV_PARALLEL */ > diff --git a/tests/unit/test-char.c b/tests/unit/test-char.c > index 649fdf64e1..76946e6f90 100644 > --- a/tests/unit/test-char.c > +++ b/tests/unit/test-char.c > @@ -1203,6 +1203,24 @@ static void char_serial_test(void) > } > #endif > > +#if defined(HAVE_CHARDEV_PARALLEL) && !defined(WIN32) > +static void char_parallel_test(void) > +{ > + QemuOpts *opts; > + Chardev *chr; > + > + opts = qemu_opts_create(qemu_find_opts("chardev"), "parallel-id", > + 1, &error_abort); > + qemu_opt_set(opts, "backend", "parallel", &error_abort); > + qemu_opt_set(opts, "path", "/dev/null", &error_abort); > + > + chr = qemu_chr_new_from_opts(opts, NULL, NULL); > + g_assert_null(chr); This is wrong. On a Linux host, qemu_chr_new_from_opts() fails, because qemu_chr_open_pp_fd()'s attempt to PPCLAIM fails. On a BSD host, it succeeds. Proposed fixup appended. Marc-André, is respinning the PR with the fixup okay, or would you prefer a v2? > + > + qemu_opts_del(opts); > +} > +#endif > + > #ifndef _WIN32 > static void char_file_fifo_test(void) > { > @@ -1544,6 +1562,9 @@ int main(int argc, char **argv) > g_test_add_func("/char/udp", char_udp_test); > #if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32) > g_test_add_func("/char/serial", char_serial_test); > +#endif > +#if defined(HAVE_CHARDEV_PARALLEL) && !defined(WIN32) > + g_test_add_func("/char/parallel", char_parallel_test); > #endif > g_test_add_func("/char/hotswap", char_hotswap_test); > g_test_add_func("/char/websocket", char_websock_test); [...] diff --git a/tests/unit/test-char.c b/tests/unit/test-char.c index e3b783c06b..f273ce5226 100644 --- a/tests/unit/test-char.c +++ b/tests/unit/test-char.c @@ -1215,7 +1215,13 @@ static void char_parallel_test(void) qemu_opt_set(opts, "path", "/dev/null", &error_abort); chr = qemu_chr_new_from_opts(opts, NULL, NULL); +#ifdef __linux__ + /* fails to PPCLAIM, see qemu_chr_open_pp_fd() */ g_assert_null(chr); +#else + g_assert_nonnull(chr); + object_unparent(OBJECT(chr)); +#endif qemu_opts_del(opts); } _______________________________________________ Devel mailing list -- devel@xxxxxxxxxxxxxxxxx To unsubscribe send an email to devel-leave@xxxxxxxxxxxxxxxxx