QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) { char host[65], port[33], width[8], height[8]; int pos; const char *p; QemuOpts *opts; Error *local_err = NULL; opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1, &local_err); if (error_is_set(&local_err)) { qerror_report_err(local_err); error_free(local_err); return NULL; } if (strstart(filename, "mon:", &p)) { filename = p; qemu_opt_set(opts, "mux", "on"); if (strcmp(filename, "stdio") == 0) { /* Monitor is muxed to stdio: do not exit on Ctrl+C by default * but pass it to the guest. Handle this only for compat syntax, * for -chardev syntax we have special option for this. * This is what -nographic did, redirecting+muxing serial+monitor * to stdio causing Ctrl+C to be passed to guest. */ qemu_opt_set(opts, "signal", "off"); } } if (strcmp(filename, "null") == 0 || strcmp(filename, "pty") == 0 || strcmp(filename, "msmouse") == 0 || strcmp(filename, "braille") == 0 || strcmp(filename, "stdio") == 0) { qemu_opt_set(opts, "backend", filename); return opts; } if (strstart(filename, "vc", &p)) { qemu_opt_set(opts, "backend", "vc"); if (*p == ':') { if (sscanf(p+1, "%8[0-9]x%8[0-9]", width, height) == 2) { /* pixels */ qemu_opt_set(opts, "width", width); qemu_opt_set(opts, "height", height); } else if (sscanf(p+1, "%8[0-9]Cx%8[0-9]C", width, height) == 2) { /* chars */ qemu_opt_set(opts, "cols", width); qemu_opt_set(opts, "rows", height); } else { goto fail; } } return opts; } if (strcmp(filename, "con:") == 0) { qemu_opt_set(opts, "backend", "console"); return opts; } if (strstart(filename, "COM", NULL)) { qemu_opt_set(opts, "backend", "serial"); qemu_opt_set(opts, "path", filename); return opts; } if (strstart(filename, "file:", &p)) { qemu_opt_set(opts, "backend", "file"); qemu_opt_set(opts, "path", p); return opts; } if (strstart(filename, "pipe:", &p)) { qemu_opt_set(opts, "backend", "pipe"); qemu_opt_set(opts, "path", p); return opts; } if (strstart(filename, "tcp:", &p) || strstart(filename, "telnet:", &p)) { if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) { host[0] = 0; if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) goto fail; } qemu_opt_set(opts, "backend", "socket"); qemu_opt_set(opts, "host", host); qemu_opt_set(opts, "port", port); if (p[pos] == ',') { if (qemu_opts_do_parse(opts, p+pos+1, NULL) != 0) goto fail; } if (strstart(filename, "telnet:", &p)) qemu_opt_set(opts, "telnet", "on"); return opts; } if (strstart(filename, "udp:", &p)) { qemu_opt_set(opts, "backend", "udp"); if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) { host[0] = 0; if (sscanf(p, ":%32[^@,]%n", port, &pos) < 1) { goto fail; } } qemu_opt_set(opts, "host", host); qemu_opt_set(opts, "port", port); if (p[pos] == '@') { p += pos + 1; if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) { host[0] = 0; if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) { goto fail; } } qemu_opt_set(opts, "localaddr", host); qemu_opt_set(opts, "localport", port); } return opts; } if (strstart(filename, "unix:", &p)) { qemu_opt_set(opts, "backend", "socket"); if (qemu_opts_do_parse(opts, p, "path") != 0) goto fail; return opts; } if (strstart(filename, "/dev/parport", NULL) || strstart(filename, "/dev/ppi", NULL)) { qemu_opt_set(opts, "backend", "parport"); qemu_opt_set(opts, "path", filename); return opts; } if (strstart(filename, "/dev/", NULL)) { qemu_opt_set(opts, "backend", "tty"); qemu_opt_set(opts, "path", filename); return opts; } fail: qemu_opts_del(opts); return NULL; }