1 #include "qemu/osdep.h"
2 #include <glib/gstdio.h>
4 #include "qemu-common.h"
5 #include "qemu/config-file.h"
6 #include "sysemu/char.h"
7 #include "sysemu/sysemu.h"
8 #include "qapi/error.h"
9 #include "qmp-commands.h"
13 typedef struct FeHandler
{
20 static void main_loop(void)
27 nonblocking
= last_io
> 0;
28 last_io
= main_loop_wait(nonblocking
);
33 static int fe_can_read(void *opaque
)
35 FeHandler
*h
= opaque
;
37 return sizeof(h
->read_buf
) - h
->read_count
;
40 static void fe_read(void *opaque
, const uint8_t *buf
, int size
)
42 FeHandler
*h
= opaque
;
44 g_assert_cmpint(size
, <=, fe_can_read(opaque
));
46 memcpy(h
->read_buf
+ h
->read_count
, buf
, size
);
47 h
->read_count
+= size
;
51 static void fe_event(void *opaque
, int event
)
53 FeHandler
*h
= opaque
;
55 h
->last_event
= event
;
59 #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
60 static void char_stdio_test_subprocess(void)
66 chr
= qemu_chr_new("label", "stdio");
67 g_assert_nonnull(chr
);
69 qemu_chr_fe_init(&be
, chr
, &error_abort
);
70 qemu_chr_fe_set_open(&be
, true);
71 ret
= qemu_chr_fe_write(&be
, (void *)"buf", 4);
72 g_assert_cmpint(ret
, ==, 4);
74 qemu_chr_fe_deinit(&be
);
75 object_unparent(OBJECT(chr
));
78 static void char_stdio_test(void)
80 g_test_trap_subprocess("/char/stdio/subprocess", 0, 0);
81 g_test_trap_assert_passed();
82 g_test_trap_assert_stdout("buf");
87 static void char_ringbuf_test(void)
95 opts
= qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
97 qemu_opt_set(opts
, "backend", "ringbuf", &error_abort
);
99 qemu_opt_set(opts
, "size", "5", &error_abort
);
100 chr
= qemu_chr_new_from_opts(opts
, NULL
);
104 opts
= qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
106 qemu_opt_set(opts
, "backend", "ringbuf", &error_abort
);
107 qemu_opt_set(opts
, "size", "2", &error_abort
);
108 chr
= qemu_chr_new_from_opts(opts
, &error_abort
);
109 g_assert_nonnull(chr
);
112 qemu_chr_fe_init(&be
, chr
, &error_abort
);
113 ret
= qemu_chr_fe_write(&be
, (void *)"buff", 4);
114 g_assert_cmpint(ret
, ==, 4);
116 data
= qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort
);
117 g_assert_cmpstr(data
, ==, "ff");
120 data
= qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort
);
121 g_assert_cmpstr(data
, ==, "");
124 qemu_chr_fe_deinit(&be
);
125 object_unparent(OBJECT(chr
));
128 opts
= qemu_opts_create(qemu_find_opts("chardev"), "memory-label",
130 qemu_opt_set(opts
, "backend", "memory", &error_abort
);
131 qemu_opt_set(opts
, "size", "2", &error_abort
);
132 chr
= qemu_chr_new_from_opts(opts
, NULL
);
133 g_assert_nonnull(chr
);
134 object_unparent(OBJECT(chr
));
138 static void char_mux_test(void)
143 FeHandler h1
= { 0, }, h2
= { 0, };
144 CharBackend chr_be1
, chr_be2
;
146 opts
= qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
148 qemu_opt_set(opts
, "backend", "ringbuf", &error_abort
);
149 qemu_opt_set(opts
, "size", "128", &error_abort
);
150 qemu_opt_set(opts
, "mux", "on", &error_abort
);
151 chr
= qemu_chr_new_from_opts(opts
, &error_abort
);
152 g_assert_nonnull(chr
);
155 qemu_chr_fe_init(&chr_be1
, chr
, &error_abort
);
156 qemu_chr_fe_set_handlers(&chr_be1
,
163 qemu_chr_fe_init(&chr_be2
, chr
, &error_abort
);
164 qemu_chr_fe_set_handlers(&chr_be2
,
170 qemu_chr_fe_take_focus(&chr_be2
);
172 base
= qemu_chr_find("mux-label-base");
173 g_assert_cmpint(qemu_chr_be_can_write(base
), !=, 0);
175 qemu_chr_be_write(base
, (void *)"hello", 6);
176 g_assert_cmpint(h1
.read_count
, ==, 0);
177 g_assert_cmpint(h2
.read_count
, ==, 6);
178 g_assert_cmpstr(h2
.read_buf
, ==, "hello");
182 qemu_chr_be_write(base
, (void *)"\1c", 2);
184 qemu_chr_be_write(base
, (void *)"hello", 6);
185 g_assert_cmpint(h2
.read_count
, ==, 0);
186 g_assert_cmpint(h1
.read_count
, ==, 6);
187 g_assert_cmpstr(h1
.read_buf
, ==, "hello");
190 /* remove first handler */
191 qemu_chr_fe_set_handlers(&chr_be1
, NULL
, NULL
, NULL
, NULL
, NULL
, true);
192 qemu_chr_be_write(base
, (void *)"hello", 6);
193 g_assert_cmpint(h1
.read_count
, ==, 0);
194 g_assert_cmpint(h2
.read_count
, ==, 0);
196 qemu_chr_be_write(base
, (void *)"\1c", 2);
197 qemu_chr_be_write(base
, (void *)"hello", 6);
198 g_assert_cmpint(h1
.read_count
, ==, 0);
199 g_assert_cmpint(h2
.read_count
, ==, 6);
200 g_assert_cmpstr(h2
.read_buf
, ==, "hello");
204 qemu_chr_be_write(base
, (void *)"\1?", 2);
205 data
= qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort
);
206 g_assert_cmpint(strlen(data
), !=, 0);
209 qemu_chr_fe_deinit(&chr_be1
);
210 qemu_chr_fe_deinit(&chr_be2
);
211 object_unparent(OBJECT(chr
));
215 static void char_pipe_test(void)
217 gchar
*tmp_path
= g_dir_make_tmp("qemu-test-char.XXXXXX", NULL
);
218 gchar
*tmp
, *in
, *out
, *pipe
= g_build_filename(tmp_path
, "pipe", NULL
);
223 FeHandler fe
= { 0, };
225 in
= g_strdup_printf("%s.in", pipe
);
226 if (mkfifo(in
, 0600) < 0) {
229 out
= g_strdup_printf("%s.out", pipe
);
230 if (mkfifo(out
, 0600) < 0) {
234 tmp
= g_strdup_printf("pipe:%s", pipe
);
235 chr
= qemu_chr_new("pipe", tmp
);
236 g_assert_nonnull(chr
);
239 qemu_chr_fe_init(&be
, chr
, &error_abort
);
241 ret
= qemu_chr_fe_write(&be
, (void *)"pipe-out", 9);
242 g_assert_cmpint(ret
, ==, 9);
244 fd
= open(out
, O_RDWR
);
245 ret
= read(fd
, buf
, sizeof(buf
));
246 g_assert_cmpint(ret
, ==, 9);
247 g_assert_cmpstr(buf
, ==, "pipe-out");
250 fd
= open(in
, O_WRONLY
);
251 ret
= write(fd
, "pipe-in", 8);
252 g_assert_cmpint(ret
, ==, 8);
255 qemu_chr_fe_set_handlers(&be
,
264 g_assert_cmpint(fe
.read_count
, ==, 8);
265 g_assert_cmpstr(fe
.read_buf
, ==, "pipe-in");
267 qemu_chr_fe_deinit(&be
);
268 object_unparent(OBJECT(chr
));
270 g_assert(g_unlink(in
) == 0);
271 g_assert(g_unlink(out
) == 0);
272 g_assert(g_rmdir(tmp_path
) == 0);
280 static void char_file_test(void)
282 char *tmp_path
= g_dir_make_tmp("qemu-test-char.XXXXXX", NULL
);
283 char *out
= g_build_filename(tmp_path
, "out", NULL
);
284 char *contents
= NULL
;
285 ChardevFile file
= { .out
= out
};
286 ChardevBackend backend
= { .type
= CHARDEV_BACKEND_KIND_FILE
,
287 .u
.file
.data
= &file
};
292 chr
= qemu_chardev_new(NULL
, TYPE_CHARDEV_FILE
, &backend
,
294 ret
= qemu_chr_write_all(chr
, (uint8_t *)"hello!", 6);
295 g_assert_cmpint(ret
, ==, 6);
296 object_unref(OBJECT(chr
));
298 ret
= g_file_get_contents(out
, &contents
, &length
, NULL
);
299 g_assert(ret
== TRUE
);
300 g_assert_cmpint(length
, ==, 6);
301 g_assert(strncmp(contents
, "hello!", 6) == 0);
307 FeHandler fe
= { 0, };
308 char *fifo
= g_build_filename(tmp_path
, "fifo", NULL
);
311 if (mkfifo(fifo
, 0600) < 0) {
315 fd
= open(fifo
, O_RDWR
);
316 ret
= write(fd
, "fifo-in", 8);
317 g_assert_cmpint(ret
, ==, 8);
321 chr
= qemu_chardev_new(NULL
, TYPE_CHARDEV_FILE
, &backend
,
324 qemu_chr_fe_init(&be
, chr
, &error_abort
);
325 qemu_chr_fe_set_handlers(&be
,
335 g_assert_cmpint(fe
.read_count
, ==, 8);
336 g_assert_cmpstr(fe
.read_buf
, ==, "fifo-in");
337 qemu_chr_fe_deinit(&be
);
338 object_unref(OBJECT(chr
));
350 static void char_null_test(void)
357 chr
= qemu_chr_find("label-null");
360 chr
= qemu_chr_new("label-null", "null");
361 chr
= qemu_chr_find("label-null");
362 g_assert_nonnull(chr
);
364 g_assert(qemu_chr_has_feature(chr
,
365 QEMU_CHAR_FEATURE_FD_PASS
) == false);
366 g_assert(qemu_chr_has_feature(chr
,
367 QEMU_CHAR_FEATURE_RECONNECTABLE
) == false);
369 /* check max avail */
370 qemu_chr_fe_init(&be
, chr
, &error_abort
);
371 qemu_chr_fe_init(&be
, chr
, &err
);
372 error_free_or_abort(&err
);
374 /* deinit & reinit */
375 qemu_chr_fe_deinit(&be
);
376 qemu_chr_fe_init(&be
, chr
, &error_abort
);
378 qemu_chr_fe_set_open(&be
, true);
380 qemu_chr_fe_set_handlers(&be
,
386 ret
= qemu_chr_fe_write(&be
, (void *)"buf", 4);
387 g_assert_cmpint(ret
, ==, 4);
389 qemu_chr_fe_deinit(&be
);
390 object_unparent(OBJECT(chr
));
393 static void char_invalid_test(void)
397 chr
= qemu_chr_new("label-invalid", "invalid");
401 int main(int argc
, char **argv
)
403 qemu_init_main_loop(&error_abort
);
405 g_test_init(&argc
, &argv
, NULL
);
407 module_call_init(MODULE_INIT_QOM
);
408 qemu_add_opts(&qemu_chardev_opts
);
410 g_test_add_func("/char/null", char_null_test
);
411 g_test_add_func("/char/invalid", char_invalid_test
);
412 g_test_add_func("/char/ringbuf", char_ringbuf_test
);
413 g_test_add_func("/char/mux", char_mux_test
);
414 #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
415 g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess
);
416 g_test_add_func("/char/stdio", char_stdio_test
);
419 g_test_add_func("/char/pipe", char_pipe_test
);
421 g_test_add_func("/char/file", char_file_test
);