X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/a0430dd8abb8a2f31c5ee919daab2e3d76353c04..6bb58d200a9e68808e856df76a0e2fd3bf38e35d:/monitor.c diff --git a/monitor.c b/monitor.c index 33ccbf3957..bb48997913 100644 --- a/monitor.c +++ b/monitor.c @@ -51,7 +51,8 @@ #include "sysemu/balloon.h" #include "qemu/timer.h" #include "sysemu/hw_accel.h" -#include "qemu/acl.h" +#include "authz/list.h" +#include "qapi/util.h" #include "sysemu/tpm.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" @@ -249,8 +250,6 @@ QEMUBH *qmp_dispatcher_bh; struct QMPRequest { /* Owner of the request */ Monitor *mon; - /* "id" field of the request */ - QObject *id; /* * Request object to be handled or Error to be reported * (exactly one of them is non-null) @@ -352,7 +351,6 @@ int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func, static void qmp_request_free(QMPRequest *req) { - qobject_unref(req->id); qobject_unref(req->req); error_free(req->err); g_free(req); @@ -432,15 +430,14 @@ void monitor_flush(Monitor *mon) } /* flush at every end of line */ -static void monitor_puts(Monitor *mon, const char *str) +static int monitor_puts(Monitor *mon, const char *str) { + int i; char c; qemu_mutex_lock(&mon->mon_lock); - for(;;) { - c = *str++; - if (c == '\0') - break; + for (i = 0; str[i]; i++) { + c = str[i]; if (c == '\n') { qstring_append_chr(mon->outbuf, '\r'); } @@ -450,39 +447,37 @@ static void monitor_puts(Monitor *mon, const char *str) } } qemu_mutex_unlock(&mon->mon_lock); + + return i; } -void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) +int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { char *buf; + int n; if (!mon) - return; + return -1; if (monitor_is_qmp(mon)) { - return; + return -1; } buf = g_strdup_vprintf(fmt, ap); - monitor_puts(mon, buf); + n = monitor_puts(mon, buf); g_free(buf); + return n; } -void monitor_printf(Monitor *mon, const char *fmt, ...) +int monitor_printf(Monitor *mon, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - monitor_vprintf(mon, fmt, ap); - va_end(ap); -} + int ret; -int monitor_fprintf(FILE *stream, const char *fmt, ...) -{ va_list ap; va_start(ap, fmt); - monitor_vprintf((Monitor *)stream, fmt, ap); + ret = monitor_vprintf(mon, fmt, ap); va_end(ap); - return 0; + return ret; } static void qmp_send_response(Monitor *mon, const QDict *rsp) @@ -1050,7 +1045,7 @@ static void hmp_trace_file(Monitor *mon, const QDict *qdict) const char *arg = qdict_get_try_str(qdict, "arg"); if (!op) { - st_print_trace_file_status((FILE *)mon, &monitor_fprintf); + st_print_trace_file_status(); } else if (!strcmp(op, "on")) { st_set_trace_file_enabled(true); } else if (!strcmp(op, "off")) { @@ -1290,7 +1285,7 @@ static void hmp_info_registers(Monitor *mon, const QDict *qdict) if (all_cpus) { CPU_FOREACH(cs) { monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index); - cpu_dump_state(cs, (FILE *)mon, monitor_fprintf, CPU_DUMP_FPU); + cpu_dump_state(cs, NULL, CPU_DUMP_FPU); } } else { cs = mon_get_cpu(); @@ -1300,7 +1295,7 @@ static void hmp_info_registers(Monitor *mon, const QDict *qdict) return; } - cpu_dump_state(cs, (FILE *)mon, monitor_fprintf, CPU_DUMP_FPU); + cpu_dump_state(cs, NULL, CPU_DUMP_FPU); } } @@ -1312,13 +1307,13 @@ static void hmp_info_jit(Monitor *mon, const QDict *qdict) return; } - dump_exec_info((FILE *)mon, monitor_fprintf); - dump_drift_info((FILE *)mon, monitor_fprintf); + dump_exec_info(); + dump_drift_info(); } static void hmp_info_opcount(Monitor *mon, const QDict *qdict) { - dump_opcount_info((FILE *)mon, monitor_fprintf); + dump_opcount_info(); } #endif @@ -1330,7 +1325,7 @@ static void hmp_info_sync_profile(Monitor *mon, const QDict *qdict) enum QSPSortBy sort_by; sort_by = mean ? QSP_SORT_BY_AVG_WAIT_TIME : QSP_SORT_BY_TOTAL_WAIT_TIME; - qsp_report((FILE *)mon, monitor_fprintf, max, sort_by, coalesce); + qsp_report(max, sort_by, coalesce); } static void hmp_info_history(Monitor *mon, const QDict *qdict) @@ -1358,7 +1353,7 @@ static void hmp_info_cpustats(Monitor *mon, const QDict *qdict) monitor_printf(mon, "No CPU available\n"); return; } - cpu_dump_statistics(cs, (FILE *)mon, &monitor_fprintf, 0); + cpu_dump_statistics(cs, 0); } static void hmp_info_trace_events(Monitor *mon, const QDict *qdict) @@ -1678,6 +1673,28 @@ static void hmp_gpa2hva(Monitor *mon, const QDict *qdict) memory_region_unref(mr); } +static void hmp_gva2gpa(Monitor *mon, const QDict *qdict) +{ + target_ulong addr = qdict_get_int(qdict, "addr"); + MemTxAttrs attrs; + CPUState *cs = mon_get_cpu(); + hwaddr gpa; + + if (!cs) { + monitor_printf(mon, "No cpu\n"); + return; + } + + gpa = cpu_get_phys_page_attrs_debug(mon_get_cpu(), + addr & TARGET_PAGE_MASK, &attrs); + if (gpa == -1) { + monitor_printf(mon, "Unmapped\n"); + } else { + monitor_printf(mon, "gpa: %#" HWADDR_PRIx "\n", + gpa + (addr & ~TARGET_PAGE_MASK)); + } +} + #ifdef CONFIG_LINUX static uint64_t vtop(void *ptr, Error **errp) { @@ -1901,8 +1918,7 @@ static void hmp_info_mtree(Monitor *mon, const QDict *qdict) bool dispatch_tree = qdict_get_try_bool(qdict, "dispatch_tree", false); bool owner = qdict_get_try_bool(qdict, "owner", false); - mtree_info((fprintf_function)monitor_printf, mon, flatview, dispatch_tree, - owner); + mtree_info(flatview, dispatch_tree, owner); } static void hmp_info_numa(Monitor *mon, const QDict *qdict) @@ -2016,93 +2032,169 @@ static void hmp_wavcapture(Monitor *mon, const QDict *qdict) QLIST_INSERT_HEAD (&capture_head, s, entries); } -static qemu_acl *find_acl(Monitor *mon, const char *name) +static QAuthZList *find_auth(Monitor *mon, const char *name) { - qemu_acl *acl = qemu_acl_find(name); + Object *obj; + Object *container; - if (!acl) { + container = object_get_objects_root(); + obj = object_resolve_path_component(container, name); + if (!obj) { monitor_printf(mon, "acl: unknown list '%s'\n", name); + return NULL; } - return acl; + + return QAUTHZ_LIST(obj); +} + +static bool warn_acl; +static void hmp_warn_acl(void) +{ + if (warn_acl) { + return; + } + error_report("The acl_show, acl_reset, acl_policy, acl_add, acl_remove " + "commands are deprecated with no replacement. Authorization " + "for VNC should be performed using the pluggable QAuthZ " + "objects"); + warn_acl = true; } static void hmp_acl_show(Monitor *mon, const QDict *qdict) { const char *aclname = qdict_get_str(qdict, "aclname"); - qemu_acl *acl = find_acl(mon, aclname); - qemu_acl_entry *entry; - int i = 0; - - if (acl) { - monitor_printf(mon, "policy: %s\n", - acl->defaultDeny ? "deny" : "allow"); - QTAILQ_FOREACH(entry, &acl->entries, next) { - i++; - monitor_printf(mon, "%d: %s %s\n", i, - entry->deny ? "deny" : "allow", entry->match); - } + QAuthZList *auth = find_auth(mon, aclname); + QAuthZListRuleList *rules; + size_t i = 0; + + hmp_warn_acl(); + + if (!auth) { + return; + } + + monitor_printf(mon, "policy: %s\n", + QAuthZListPolicy_str(auth->policy)); + + rules = auth->rules; + while (rules) { + QAuthZListRule *rule = rules->value; + i++; + monitor_printf(mon, "%zu: %s %s\n", i, + QAuthZListPolicy_str(rule->policy), + rule->match); + rules = rules->next; } } static void hmp_acl_reset(Monitor *mon, const QDict *qdict) { const char *aclname = qdict_get_str(qdict, "aclname"); - qemu_acl *acl = find_acl(mon, aclname); + QAuthZList *auth = find_auth(mon, aclname); - if (acl) { - qemu_acl_reset(acl); - monitor_printf(mon, "acl: removed all rules\n"); + hmp_warn_acl(); + + if (!auth) { + return; } + + auth->policy = QAUTHZ_LIST_POLICY_DENY; + qapi_free_QAuthZListRuleList(auth->rules); + auth->rules = NULL; + monitor_printf(mon, "acl: removed all rules\n"); } static void hmp_acl_policy(Monitor *mon, const QDict *qdict) { const char *aclname = qdict_get_str(qdict, "aclname"); const char *policy = qdict_get_str(qdict, "policy"); - qemu_acl *acl = find_acl(mon, aclname); + QAuthZList *auth = find_auth(mon, aclname); + int val; + Error *err = NULL; + + hmp_warn_acl(); + + if (!auth) { + return; + } - if (acl) { - if (strcmp(policy, "allow") == 0) { - acl->defaultDeny = 0; + val = qapi_enum_parse(&QAuthZListPolicy_lookup, + policy, + QAUTHZ_LIST_POLICY_DENY, + &err); + if (err) { + error_free(err); + monitor_printf(mon, "acl: unknown policy '%s', " + "expected 'deny' or 'allow'\n", policy); + } else { + auth->policy = val; + if (auth->policy == QAUTHZ_LIST_POLICY_ALLOW) { monitor_printf(mon, "acl: policy set to 'allow'\n"); - } else if (strcmp(policy, "deny") == 0) { - acl->defaultDeny = 1; - monitor_printf(mon, "acl: policy set to 'deny'\n"); } else { - monitor_printf(mon, "acl: unknown policy '%s', " - "expected 'deny' or 'allow'\n", policy); + monitor_printf(mon, "acl: policy set to 'deny'\n"); } } } +static QAuthZListFormat hmp_acl_get_format(const char *match) +{ + if (strchr(match, '*')) { + return QAUTHZ_LIST_FORMAT_GLOB; + } else { + return QAUTHZ_LIST_FORMAT_EXACT; + } +} + static void hmp_acl_add(Monitor *mon, const QDict *qdict) { const char *aclname = qdict_get_str(qdict, "aclname"); const char *match = qdict_get_str(qdict, "match"); - const char *policy = qdict_get_str(qdict, "policy"); + const char *policystr = qdict_get_str(qdict, "policy"); int has_index = qdict_haskey(qdict, "index"); int index = qdict_get_try_int(qdict, "index", -1); - qemu_acl *acl = find_acl(mon, aclname); - int deny, ret; - - if (acl) { - if (strcmp(policy, "allow") == 0) { - deny = 0; - } else if (strcmp(policy, "deny") == 0) { - deny = 1; - } else { - monitor_printf(mon, "acl: unknown policy '%s', " - "expected 'deny' or 'allow'\n", policy); - return; - } - if (has_index) - ret = qemu_acl_insert(acl, deny, match, index); - else - ret = qemu_acl_append(acl, deny, match); - if (ret < 0) - monitor_printf(mon, "acl: unable to add acl entry\n"); - else - monitor_printf(mon, "acl: added rule at position %d\n", ret); + QAuthZList *auth = find_auth(mon, aclname); + Error *err = NULL; + QAuthZListPolicy policy; + QAuthZListFormat format; + size_t i = 0; + + hmp_warn_acl(); + + if (!auth) { + return; + } + + policy = qapi_enum_parse(&QAuthZListPolicy_lookup, + policystr, + QAUTHZ_LIST_POLICY_DENY, + &err); + if (err) { + error_free(err); + monitor_printf(mon, "acl: unknown policy '%s', " + "expected 'deny' or 'allow'\n", policystr); + return; + } + + format = hmp_acl_get_format(match); + + if (has_index && index == 0) { + monitor_printf(mon, "acl: unable to add acl entry\n"); + return; + } + + if (has_index) { + i = qauthz_list_insert_rule(auth, match, policy, + format, index - 1, &err); + } else { + i = qauthz_list_append_rule(auth, match, policy, + format, &err); + } + if (err) { + monitor_printf(mon, "acl: unable to add rule: %s", + error_get_pretty(err)); + error_free(err); + } else { + monitor_printf(mon, "acl: added rule at position %zu\n", i + 1); } } @@ -2110,15 +2202,20 @@ static void hmp_acl_remove(Monitor *mon, const QDict *qdict) { const char *aclname = qdict_get_str(qdict, "aclname"); const char *match = qdict_get_str(qdict, "match"); - qemu_acl *acl = find_acl(mon, aclname); - int ret; + QAuthZList *auth = find_auth(mon, aclname); + ssize_t i = 0; - if (acl) { - ret = qemu_acl_remove(acl, match); - if (ret < 0) - monitor_printf(mon, "acl: no matching acl entry\n"); - else - monitor_printf(mon, "acl: removed rule at position %d\n", ret); + hmp_warn_acl(); + + if (!auth) { + return; + } + + i = qauthz_list_delete_rule(auth, match); + if (i >= 0) { + monitor_printf(mon, "acl: removed rule at position %zu\n", i + 1); + } else { + monitor_printf(mon, "acl: no matching acl entry\n"); } } @@ -4026,18 +4123,14 @@ static int monitor_can_read(void *opaque) * Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP. * Nothing is emitted then. */ -static void monitor_qmp_respond(Monitor *mon, QDict *rsp, QObject *id) +static void monitor_qmp_respond(Monitor *mon, QDict *rsp) { if (rsp) { - if (id) { - qdict_put_obj(rsp, "id", qobject_ref(id)); - } - qmp_send_response(mon, rsp); } } -static void monitor_qmp_dispatch(Monitor *mon, QObject *req, QObject *id) +static void monitor_qmp_dispatch(Monitor *mon, QObject *req) { Monitor *old_mon; QDict *rsp; @@ -4062,7 +4155,7 @@ static void monitor_qmp_dispatch(Monitor *mon, QObject *req, QObject *id) } } - monitor_qmp_respond(mon, rsp, id); + monitor_qmp_respond(mon, rsp); qobject_unref(rsp); } @@ -4126,13 +4219,15 @@ static void monitor_qmp_bh_dispatcher(void *data) mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1; qemu_mutex_unlock(&mon->qmp.qmp_queue_lock); if (req_obj->req) { - trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: ""); - monitor_qmp_dispatch(mon, req_obj->req, req_obj->id); + QDict *qdict = qobject_to(QDict, req_obj->req); + QObject *id = qdict ? qdict_get(qdict, "id") : NULL; + trace_monitor_qmp_cmd_in_band(qobject_get_try_str(id) ?: ""); + monitor_qmp_dispatch(mon, req_obj->req); } else { assert(req_obj->err); rsp = qmp_error_response(req_obj->err); req_obj->err = NULL; - monitor_qmp_respond(mon, rsp, NULL); + monitor_qmp_respond(mon, rsp); qobject_unref(rsp); } @@ -4157,8 +4252,7 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err) qdict = qobject_to(QDict, req); if (qdict) { - id = qobject_ref(qdict_get(qdict, "id")); - qdict_del(qdict, "id"); + id = qdict_get(qdict, "id"); } /* else will fail qmp_dispatch() */ if (req && trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) { @@ -4169,17 +4263,14 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err) if (qdict && qmp_is_oob(qdict)) { /* OOB commands are executed immediately */ - trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(id) - ?: ""); - monitor_qmp_dispatch(mon, req, id); + trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(id) ?: ""); + monitor_qmp_dispatch(mon, req); qobject_unref(req); - qobject_unref(id); return; } req_obj = g_new0(QMPRequest, 1); req_obj->mon = mon; - req_obj->id = id; req_obj->req = req; req_obj->err = err; @@ -4199,7 +4290,7 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err) /* * Put the request to the end of queue so that requests will be - * handled in time order. Ownership for req_obj, req, id, + * handled in time order. Ownership for req_obj, req, * etc. will be delivered to the handler side. */ assert(mon->qmp.qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX); @@ -4461,36 +4552,25 @@ static void monitor_readline_flush(void *opaque) } /* - * Print to current monitor if we have one, else to stream. - * TODO should return int, so callers can calculate width, but that - * requires surgery to monitor_vprintf(). Left for another day. + * Print to current monitor if we have one, else to stderr. */ -void monitor_vfprintf(FILE *stream, const char *fmt, va_list ap) +int error_vprintf(const char *fmt, va_list ap) { if (cur_mon && !monitor_cur_is_qmp()) { - monitor_vprintf(cur_mon, fmt, ap); - } else { - vfprintf(stream, fmt, ap); + return monitor_vprintf(cur_mon, fmt, ap); } + return vfprintf(stderr, fmt, ap); } -/* - * Print to current monitor if we have one, else to stderr. - * TODO should return int, so callers can calculate width, but that - * requires surgery to monitor_vprintf(). Left for another day. - */ -void error_vprintf(const char *fmt, va_list ap) +int error_vprintf_unless_qmp(const char *fmt, va_list ap) { - monitor_vfprintf(stderr, fmt, ap); -} - -void error_vprintf_unless_qmp(const char *fmt, va_list ap) -{ - if (cur_mon && !monitor_cur_is_qmp()) { - monitor_vprintf(cur_mon, fmt, ap); - } else if (!cur_mon) { - vfprintf(stderr, fmt, ap); + if (!cur_mon) { + return vfprintf(stderr, fmt, ap); + } + if (!monitor_cur_is_qmp()) { + return monitor_vprintf(cur_mon, fmt, ap); } + return -1; } static void monitor_list_append(Monitor *mon)