blob: e0c87edbdd489903e683480b267f8e00c4533d8b [file] [log] [blame]
Kevin Wolff3534152020-02-24 15:29:49 +01001/*
2 * QEMU storage daemon
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 * Copyright (c) 2019 Kevin Wolf <kwolf@redhat.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26#include "qemu/osdep.h"
27
28#include <getopt.h>
29
30#include "block/block.h"
Kevin Wolfeed8b692020-02-24 15:29:57 +010031#include "block/nbd.h"
Kevin Wolf5e6911c2020-02-24 15:30:01 +010032#include "chardev/char.h"
Kevin Wolff3534152020-02-24 15:29:49 +010033#include "crypto/init.h"
Kevin Wolf2af282e2020-02-24 15:30:08 +010034#include "monitor/monitor.h"
35#include "monitor/monitor-internal.h"
Kevin Wolff3534152020-02-24 15:29:49 +010036
37#include "qapi/error.h"
Kevin Wolfeed8b692020-02-24 15:29:57 +010038#include "qapi/qapi-visit-block-core.h"
Kevin Wolf5daa6bf2020-09-24 17:26:48 +020039#include "qapi/qapi-visit-block-export.h"
Kevin Wolf2af282e2020-02-24 15:30:08 +010040#include "qapi/qapi-visit-control.h"
Kevin Wolfd6da78b2020-02-24 15:29:56 +010041#include "qapi/qmp/qdict.h"
Kevin Wolf2af282e2020-02-24 15:30:08 +010042#include "qapi/qmp/qstring.h"
Kevin Wolf14837c62020-02-24 15:29:54 +010043#include "qapi/qobject-input-visitor.h"
44
Kevin Wolff3534152020-02-24 15:29:49 +010045#include "qemu-common.h"
46#include "qemu-version.h"
47#include "qemu/config-file.h"
48#include "qemu/error-report.h"
Kevin Wolfd6da78b2020-02-24 15:29:56 +010049#include "qemu/help_option.h"
Kevin Wolff3534152020-02-24 15:29:49 +010050#include "qemu/log.h"
51#include "qemu/main-loop.h"
52#include "qemu/module.h"
Kevin Wolfd6da78b2020-02-24 15:29:56 +010053#include "qemu/option.h"
54#include "qom/object_interfaces.h"
Kevin Wolff3534152020-02-24 15:29:49 +010055
Kevin Wolf2af282e2020-02-24 15:30:08 +010056#include "storage-daemon/qapi/qapi-commands.h"
57#include "storage-daemon/qapi/qapi-init-commands.h"
58
Kevin Wolfaa706832020-02-24 15:30:00 +010059#include "sysemu/runstate.h"
Kevin Wolff3534152020-02-24 15:29:49 +010060#include "trace/control.h"
61
Kevin Wolfaa706832020-02-24 15:30:00 +010062static volatile bool exit_requested = false;
63
64void qemu_system_killed(int signal, pid_t pid)
65{
66 exit_requested = true;
67}
68
Kevin Wolf2af282e2020-02-24 15:30:08 +010069void qmp_quit(Error **errp)
70{
71 exit_requested = true;
72}
73
Kevin Wolff3534152020-02-24 15:29:49 +010074static void help(void)
75{
76 printf(
77"Usage: %s [options]\n"
78"QEMU storage daemon\n"
79"\n"
80" -h, --help display this help and exit\n"
81" -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
82" specify tracing options\n"
83" -V, --version output version information and exit\n"
84"\n"
Kevin Wolf14837c62020-02-24 15:29:54 +010085" --blockdev [driver=]<driver>[,node-name=<N>][,discard=ignore|unmap]\n"
86" [,cache.direct=on|off][,cache.no-flush=on|off]\n"
87" [,read-only=on|off][,auto-read-only=on|off]\n"
88" [,force-share=on|off][,detect-zeroes=on|off|unmap]\n"
89" [,driver specific parameters...]\n"
90" configure a block backend\n"
91"\n"
Kevin Wolf5e6911c2020-02-24 15:30:01 +010092" --chardev <options> configure a character device backend\n"
93" (see the qemu(1) man page for possible options)\n"
94"\n"
Kevin Wolf45db4bc2020-09-30 15:39:09 +020095" --export [type=]nbd,id=<id>,node-name=<node-name>[,name=<export-name>]\n"
Kevin Wolf39411122020-02-24 15:29:59 +010096" [,writable=on|off][,bitmap=<name>]\n"
97" export the specified block node over NBD\n"
98" (requires --nbd-server)\n"
99"\n"
Kevin Wolf2af282e2020-02-24 15:30:08 +0100100" --monitor [chardev=]name[,mode=control][,pretty[=on|off]]\n"
101" configure a QMP monitor\n"
102"\n"
Kevin Wolfeed8b692020-02-24 15:29:57 +0100103" --nbd-server addr.type=inet,addr.host=<host>,addr.port=<port>\n"
Kevin Wolf1c8222b2020-09-24 17:26:54 +0200104" [,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]\n"
Kevin Wolfeed8b692020-02-24 15:29:57 +0100105" --nbd-server addr.type=unix,addr.path=<path>\n"
Kevin Wolf1c8222b2020-09-24 17:26:54 +0200106" [,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]\n"
Kevin Wolfeed8b692020-02-24 15:29:57 +0100107" start an NBD server for exporting block nodes\n"
108"\n"
Kevin Wolfd6da78b2020-02-24 15:29:56 +0100109" --object help list object types that can be added\n"
110" --object <type>,help list properties for the given object type\n"
111" --object <type>[,<property>=<value>...]\n"
112" create a new object of type <type>, setting\n"
113" properties in the order they are specified. Note\n"
114" that the 'id' property must be set.\n"
115" See the qemu(1) man page for documentation of the\n"
116" objects that can be added.\n"
117"\n"
Kevin Wolff3534152020-02-24 15:29:49 +0100118QEMU_HELP_BOTTOM "\n",
119 error_get_progname());
120}
121
Kevin Wolf14837c62020-02-24 15:29:54 +0100122enum {
123 OPTION_BLOCKDEV = 256,
Kevin Wolf5e6911c2020-02-24 15:30:01 +0100124 OPTION_CHARDEV,
Kevin Wolf39411122020-02-24 15:29:59 +0100125 OPTION_EXPORT,
Kevin Wolf2af282e2020-02-24 15:30:08 +0100126 OPTION_MONITOR,
Kevin Wolfeed8b692020-02-24 15:29:57 +0100127 OPTION_NBD_SERVER,
Kevin Wolfd6da78b2020-02-24 15:29:56 +0100128 OPTION_OBJECT,
129};
130
Kevin Wolf5e6911c2020-02-24 15:30:01 +0100131extern QemuOptsList qemu_chardev_opts;
132
Kevin Wolfd6da78b2020-02-24 15:29:56 +0100133static QemuOptsList qemu_object_opts = {
134 .name = "object",
135 .implied_opt_name = "qom-type",
136 .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
137 .desc = {
138 { }
139 },
Kevin Wolf14837c62020-02-24 15:29:54 +0100140};
141
Kevin Wolf2af282e2020-02-24 15:30:08 +0100142static void init_qmp_commands(void)
143{
144 qmp_init_marshal(&qmp_commands);
145 qmp_register_command(&qmp_commands, "query-qmp-schema",
146 qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
147
148 QTAILQ_INIT(&qmp_cap_negotiation_commands);
149 qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
150 qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG);
151}
152
Kevin Wolff3534152020-02-24 15:29:49 +0100153static void process_options(int argc, char *argv[])
154{
155 int c;
156
157 static const struct option long_options[] = {
Kevin Wolf14837c62020-02-24 15:29:54 +0100158 {"blockdev", required_argument, NULL, OPTION_BLOCKDEV},
Kevin Wolf5e6911c2020-02-24 15:30:01 +0100159 {"chardev", required_argument, NULL, OPTION_CHARDEV},
Kevin Wolf39411122020-02-24 15:29:59 +0100160 {"export", required_argument, NULL, OPTION_EXPORT},
Kevin Wolff3534152020-02-24 15:29:49 +0100161 {"help", no_argument, NULL, 'h'},
Kevin Wolf2af282e2020-02-24 15:30:08 +0100162 {"monitor", required_argument, NULL, OPTION_MONITOR},
Kevin Wolfeed8b692020-02-24 15:29:57 +0100163 {"nbd-server", required_argument, NULL, OPTION_NBD_SERVER},
Kevin Wolfd6da78b2020-02-24 15:29:56 +0100164 {"object", required_argument, NULL, OPTION_OBJECT},
Kevin Wolff3534152020-02-24 15:29:49 +0100165 {"trace", required_argument, NULL, 'T'},
166 {"version", no_argument, NULL, 'V'},
167 {0, 0, 0, 0}
168 };
169
170 /*
171 * In contrast to the system emulator, options are processed in the order
172 * they are given on the command lines. This means that things must be
173 * defined first before they can be referenced in another option.
174 */
175 while ((c = getopt_long(argc, argv, "hT:V", long_options, NULL)) != -1) {
176 switch (c) {
177 case '?':
178 exit(EXIT_FAILURE);
179 case 'h':
180 help();
181 exit(EXIT_SUCCESS);
182 case 'T':
Paolo Bonzini92eecff2020-11-02 06:58:41 -0500183 trace_opt_parse(optarg);
184 trace_init_file();
185 break;
Kevin Wolff3534152020-02-24 15:29:49 +0100186 case 'V':
187 printf("qemu-storage-daemon version "
188 QEMU_FULL_VERSION "\n" QEMU_COPYRIGHT "\n");
189 exit(EXIT_SUCCESS);
Kevin Wolf14837c62020-02-24 15:29:54 +0100190 case OPTION_BLOCKDEV:
191 {
192 Visitor *v;
193 BlockdevOptions *options;
194
195 v = qobject_input_visitor_new_str(optarg, "driver",
196 &error_fatal);
197
198 visit_type_BlockdevOptions(v, NULL, &options, &error_fatal);
199 visit_free(v);
200
201 qmp_blockdev_add(options, &error_fatal);
202 qapi_free_BlockdevOptions(options);
203 break;
204 }
Kevin Wolf5e6911c2020-02-24 15:30:01 +0100205 case OPTION_CHARDEV:
206 {
207 /* TODO This interface is not stable until we QAPIfy it */
208 QemuOpts *opts = qemu_opts_parse_noisily(&qemu_chardev_opts,
209 optarg, true);
210 if (opts == NULL) {
211 exit(EXIT_FAILURE);
212 }
213
214 if (!qemu_chr_new_from_opts(opts, NULL, &error_fatal)) {
215 /* No error, but NULL returned means help was printed */
216 exit(EXIT_SUCCESS);
217 }
218 qemu_opts_del(opts);
219 break;
220 }
Kevin Wolf39411122020-02-24 15:29:59 +0100221 case OPTION_EXPORT:
222 {
223 Visitor *v;
Kevin Wolf143ea762020-09-24 17:26:49 +0200224 BlockExportOptions *export;
Kevin Wolf39411122020-02-24 15:29:59 +0100225
226 v = qobject_input_visitor_new_str(optarg, "type", &error_fatal);
Kevin Wolf143ea762020-09-24 17:26:49 +0200227 visit_type_BlockExportOptions(v, NULL, &export, &error_fatal);
Kevin Wolf39411122020-02-24 15:29:59 +0100228 visit_free(v);
229
Kevin Wolf060102a2020-09-24 17:26:51 +0200230 qmp_block_export_add(export, &error_fatal);
Kevin Wolf143ea762020-09-24 17:26:49 +0200231 qapi_free_BlockExportOptions(export);
Kevin Wolf39411122020-02-24 15:29:59 +0100232 break;
233 }
Kevin Wolf2af282e2020-02-24 15:30:08 +0100234 case OPTION_MONITOR:
235 {
236 Visitor *v;
237 MonitorOptions *monitor;
238
239 v = qobject_input_visitor_new_str(optarg, "chardev",
240 &error_fatal);
241 visit_type_MonitorOptions(v, NULL, &monitor, &error_fatal);
242 visit_free(v);
243
244 /* TODO Catch duplicate monitor IDs */
245 monitor_init(monitor, false, &error_fatal);
246 qapi_free_MonitorOptions(monitor);
247 break;
248 }
Kevin Wolfeed8b692020-02-24 15:29:57 +0100249 case OPTION_NBD_SERVER:
250 {
251 Visitor *v;
252 NbdServerOptions *options;
253
254 v = qobject_input_visitor_new_str(optarg, NULL, &error_fatal);
255 visit_type_NbdServerOptions(v, NULL, &options, &error_fatal);
256 visit_free(v);
257
258 nbd_server_start_options(options, &error_fatal);
259 qapi_free_NbdServerOptions(options);
260 break;
261 }
Kevin Wolfd6da78b2020-02-24 15:29:56 +0100262 case OPTION_OBJECT:
263 {
Kevin Wolfd6da78b2020-02-24 15:29:56 +0100264 QDict *args;
Kevin Wolf8db1efd2020-10-07 18:49:03 +0200265 bool help;
Kevin Wolfd6da78b2020-02-24 15:29:56 +0100266
Kevin Wolf8db1efd2020-10-07 18:49:03 +0200267 args = keyval_parse(optarg, "qom-type", &help, &error_fatal);
268 if (help) {
269 user_creatable_print_help_from_qdict(args);
Kevin Wolfd6da78b2020-02-24 15:29:56 +0100270 exit(EXIT_SUCCESS);
271 }
Kevin Wolfeaae29e2020-04-16 17:26:06 +0200272 user_creatable_add_dict(args, true, &error_fatal);
Kevin Wolfd6da78b2020-02-24 15:29:56 +0100273 qobject_unref(args);
Kevin Wolfd6da78b2020-02-24 15:29:56 +0100274 break;
275 }
Kevin Wolff3534152020-02-24 15:29:49 +0100276 default:
277 g_assert_not_reached();
278 }
279 }
280 if (optind != argc) {
281 error_report("Unexpected argument: %s", argv[optind]);
282 exit(EXIT_FAILURE);
283 }
284}
285
286int main(int argc, char *argv[])
287{
288#ifdef CONFIG_POSIX
289 signal(SIGPIPE, SIG_IGN);
290#endif
291
292 error_init(argv[0]);
293 qemu_init_exec_dir(argv[0]);
Kevin Wolfaa706832020-02-24 15:30:00 +0100294 os_setup_signal_handling();
Kevin Wolff3534152020-02-24 15:29:49 +0100295
296 module_call_init(MODULE_INIT_QOM);
297 module_call_init(MODULE_INIT_TRACE);
Stefan Hajnoczi5b99bde2020-06-19 11:11:31 +0100298 qemu_add_opts(&qemu_object_opts);
Kevin Wolff3534152020-02-24 15:29:49 +0100299 qemu_add_opts(&qemu_trace_opts);
300 qcrypto_init(&error_fatal);
301 bdrv_init();
Kevin Wolf2af282e2020-02-24 15:30:08 +0100302 monitor_init_globals_core();
303 init_qmp_commands();
Kevin Wolff3534152020-02-24 15:29:49 +0100304
305 if (!trace_init_backends()) {
306 return EXIT_FAILURE;
307 }
308 qemu_set_log(LOG_TRACE);
309
310 qemu_init_main_loop(&error_fatal);
311 process_options(argc, argv);
312
Kevin Wolfaa706832020-02-24 15:30:00 +0100313 while (!exit_requested) {
314 main_loop_wait(false);
315 }
316
Max Reitzb55a3c82020-10-27 20:05:56 +0100317 bdrv_drain_all_begin();
318 bdrv_close_all();
319
Stefan Hajnoczif10802d2020-06-19 11:11:32 +0100320 monitor_cleanup();
321 qemu_chr_cleanup();
322 user_creatable_cleanup();
323
Kevin Wolff3534152020-02-24 15:29:49 +0100324 return EXIT_SUCCESS;
325}