1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 #include "qemu/osdep.h" 3 #include "qapi/error.h" 4 #include "qapi/qapi-commands-misc.h" 5 #include "qapi/qmp/qlist.h" 6 #include "qemu/option.h" 7 #include "qemu/config-file.h" 8 #include "hw/boards.h" 9 10 static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc) 11 { 12 CommandLineParameterInfoList *param_list = NULL; 13 CommandLineParameterInfo *info; 14 int i; 15 16 for (i = 0; desc[i].name != NULL; i++) { 17 info = g_malloc0(sizeof(*info)); 18 info->name = g_strdup(desc[i].name); 19 20 switch (desc[i].type) { 21 case QEMU_OPT_STRING: 22 info->type = COMMAND_LINE_PARAMETER_TYPE_STRING; 23 break; 24 case QEMU_OPT_BOOL: 25 info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN; 26 break; 27 case QEMU_OPT_NUMBER: 28 info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER; 29 break; 30 case QEMU_OPT_SIZE: 31 info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE; 32 break; 33 } 34 35 info->help = g_strdup(desc[i].help); 36 info->q_default = g_strdup(desc[i].def_value_str); 37 38 QAPI_LIST_PREPEND(param_list, info); 39 } 40 41 return param_list; 42 } 43 44 /* remove repeated entry from the info list */ 45 static void cleanup_infolist(CommandLineParameterInfoList *head) 46 { 47 CommandLineParameterInfoList *pre_entry, *cur, *del_entry; 48 49 cur = head; 50 while (cur->next) { 51 pre_entry = head; 52 while (pre_entry != cur->next) { 53 if (!strcmp(pre_entry->value->name, cur->next->value->name)) { 54 del_entry = cur->next; 55 cur->next = cur->next->next; 56 del_entry->next = NULL; 57 qapi_free_CommandLineParameterInfoList(del_entry); 58 break; 59 } 60 pre_entry = pre_entry->next; 61 } 62 cur = cur->next; 63 } 64 } 65 66 /* merge the description items of two parameter infolists */ 67 static void connect_infolist(CommandLineParameterInfoList *head, 68 CommandLineParameterInfoList *new) 69 { 70 CommandLineParameterInfoList *cur; 71 72 cur = head; 73 while (cur->next) { 74 cur = cur->next; 75 } 76 cur->next = new; 77 } 78 79 /* access all the local QemuOptsLists for drive option */ 80 static CommandLineParameterInfoList *get_drive_infolist(void) 81 { 82 CommandLineParameterInfoList *head = NULL, *cur; 83 int i; 84 85 for (i = 0; drive_config_groups[i] != NULL; i++) { 86 if (!head) { 87 head = query_option_descs(drive_config_groups[i]->desc); 88 } else { 89 cur = query_option_descs(drive_config_groups[i]->desc); 90 connect_infolist(head, cur); 91 } 92 } 93 cleanup_infolist(head); 94 95 return head; 96 } 97 98 static CommandLineParameterInfo *objprop_to_cmdline_prop(ObjectProperty *prop) 99 { 100 CommandLineParameterInfo *info; 101 102 info = g_malloc0(sizeof(*info)); 103 info->name = g_strdup(prop->name); 104 105 if (g_str_equal(prop->type, "bool") || g_str_equal(prop->type, "OnOffAuto")) { 106 info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN; 107 } else if (g_str_equal(prop->type, "int")) { 108 info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER; 109 } else if (g_str_equal(prop->type, "size")) { 110 info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE; 111 } else { 112 info->type = COMMAND_LINE_PARAMETER_TYPE_STRING; 113 } 114 115 if (prop->description) { 116 info->help = g_strdup(prop->description); 117 } 118 119 return info; 120 } 121 122 static CommandLineParameterInfoList *query_all_machine_properties(void) 123 { 124 CommandLineParameterInfoList *params = NULL, *clpiter; 125 CommandLineParameterInfo *info; 126 GSList *machines, *curr_mach; 127 ObjectPropertyIterator op_iter; 128 ObjectProperty *prop; 129 bool is_new; 130 131 machines = object_class_get_list(TYPE_MACHINE, false); 132 assert(machines); 133 134 /* Loop over all machine classes */ 135 for (curr_mach = machines; curr_mach; curr_mach = curr_mach->next) { 136 object_class_property_iter_init(&op_iter, curr_mach->data); 137 /* ... and over the properties of each machine: */ 138 while ((prop = object_property_iter_next(&op_iter))) { 139 if (!prop->set) { 140 continue; 141 } 142 /* 143 * Check whether the property has already been put into the list 144 * (via another machine class) 145 */ 146 is_new = true; 147 for (clpiter = params; clpiter != NULL; clpiter = clpiter->next) { 148 if (g_str_equal(clpiter->value->name, prop->name)) { 149 is_new = false; 150 break; 151 } 152 } 153 /* If it hasn't been added before, add it now to the list */ 154 if (is_new) { 155 info = objprop_to_cmdline_prop(prop); 156 QAPI_LIST_PREPEND(params, info); 157 } 158 } 159 } 160 161 g_slist_free(machines); 162 163 /* Add entry for the "type" parameter */ 164 info = g_malloc0(sizeof(*info)); 165 info->name = g_strdup("type"); 166 info->type = COMMAND_LINE_PARAMETER_TYPE_STRING; 167 info->help = g_strdup("machine type"); 168 QAPI_LIST_PREPEND(params, info); 169 170 return params; 171 } 172 173 CommandLineOptionInfoList *qmp_query_command_line_options(const char *option, 174 Error **errp) 175 { 176 CommandLineOptionInfoList *conf_list = NULL; 177 CommandLineOptionInfo *info; 178 int i; 179 180 for (i = 0; vm_config_groups[i] != NULL; i++) { 181 if (!option || !strcmp(option, vm_config_groups[i]->name)) { 182 info = g_malloc0(sizeof(*info)); 183 info->option = g_strdup(vm_config_groups[i]->name); 184 if (!strcmp("drive", vm_config_groups[i]->name)) { 185 info->parameters = get_drive_infolist(); 186 } else { 187 info->parameters = 188 query_option_descs(vm_config_groups[i]->desc); 189 } 190 QAPI_LIST_PREPEND(conf_list, info); 191 } 192 } 193 194 if (!option || !strcmp(option, "machine")) { 195 info = g_malloc0(sizeof(*info)); 196 info->option = g_strdup("machine"); 197 info->parameters = query_all_machine_properties(); 198 QAPI_LIST_PREPEND(conf_list, info); 199 } 200 201 if (conf_list == NULL) { 202 error_setg(errp, "invalid option name: %s", option); 203 } 204 205 return conf_list; 206 } 207