1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include "qemu/osdep.h"
27
28#include <getopt.h>
29
30#include "block/block.h"
31#include "block/nbd.h"
32#include "chardev/char.h"
33#include "crypto/init.h"
34#include "monitor/monitor.h"
35#include "monitor/monitor-internal.h"
36
37#include "qapi/error.h"
38#include "qapi/qapi-visit-block-core.h"
39#include "qapi/qapi-visit-block-export.h"
40#include "qapi/qapi-visit-control.h"
41#include "qapi/qmp/qdict.h"
42#include "qapi/qmp/qstring.h"
43#include "qapi/qobject-input-visitor.h"
44
45#include "qemu/help-texts.h"
46#include "qemu-version.h"
47#include "qemu/cutils.h"
48#include "qemu/config-file.h"
49#include "qemu/error-report.h"
50#include "qemu/help_option.h"
51#include "qemu/job.h"
52#include "qemu/log.h"
53#include "qemu/main-loop.h"
54#include "qemu/module.h"
55#include "qemu/option.h"
56#include "qom/object_interfaces.h"
57
58#include "storage-daemon/qapi/qapi-commands.h"
59#include "storage-daemon/qapi/qapi-init-commands.h"
60
61#include "sysemu/runstate.h"
62#include "trace/control.h"
63
64static const char *pid_file;
65static char *pid_file_realpath;
66static volatile bool exit_requested = false;
67
68void qemu_system_killed(int signal, pid_t pid)
69{
70 exit_requested = true;
71}
72
73void qmp_quit(Error **errp)
74{
75 exit_requested = true;
76}
77
78static void help(void)
79{
80 printf(
81"Usage: %s [options]\n"
82"QEMU storage daemon\n"
83"\n"
84" -h, --help display this help and exit\n"
85" -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
86" specify tracing options\n"
87" -V, --version output version information and exit\n"
88"\n"
89" --blockdev [driver=]<driver>[,node-name=<N>][,discard=ignore|unmap]\n"
90" [,cache.direct=on|off][,cache.no-flush=on|off]\n"
91" [,read-only=on|off][,auto-read-only=on|off]\n"
92" [,force-share=on|off][,detect-zeroes=on|off|unmap]\n"
93" [,driver specific parameters...]\n"
94" configure a block backend\n"
95"\n"
96" --chardev <options> configure a character device backend\n"
97" (see the qemu(1) man page for possible options)\n"
98"\n"
99" --daemonize daemonize the process, and have the parent exit\n"
100" once startup is complete\n"
101"\n"
102" --export [type=]nbd,id=<id>,node-name=<node-name>[,name=<export-name>]\n"
103" [,writable=on|off][,bitmap=<name>]\n"
104" export the specified block node over NBD\n"
105" (requires --nbd-server)\n"
106"\n"
107#ifdef CONFIG_FUSE
108" --export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>\n"
109" [,growable=on|off][,writable=on|off][,allow-other=on|off|auto]\n"
110" export the specified block node over FUSE\n"
111"\n"
112#endif
113#ifdef CONFIG_VHOST_USER_BLK_SERVER
114" --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,\n"
115" addr.type=unix,addr.path=<socket-path>[,writable=on|off]\n"
116" [,logical-block-size=<block-size>][,num-queues=<num-queues>]\n"
117" export the specified block node as a\n"
118" vhost-user-blk device over UNIX domain socket\n"
119" --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,\n"
120" addr.type=fd,addr.str=<fd>[,writable=on|off]\n"
121" [,logical-block-size=<block-size>][,num-queues=<num-queues>]\n"
122" export the specified block node as a\n"
123" vhost-user-blk device over file descriptor\n"
124"\n"
125#endif
126#ifdef CONFIG_VDUSE_BLK_EXPORT
127" --export [type=]vduse-blk,id=<id>,node-name=<node-name>\n"
128" ,name=<vduse-name>[,writable=on|off]\n"
129" [,num-queues=<num-queues>][,queue-size=<queue-size>]\n"
130" [,logical-block-size=<logical-block-size>]\n"
131" [,serial=<serial-number>]\n"
132" export the specified block node as a\n"
133" vduse-blk device\n"
134"\n"
135#endif
136" --monitor [chardev=]name[,mode=control][,pretty[=on|off]]\n"
137" configure a QMP monitor\n"
138"\n"
139" --nbd-server addr.type=inet,addr.host=<host>,addr.port=<port>\n"
140" [,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]\n"
141" --nbd-server addr.type=unix,addr.path=<path>\n"
142" [,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]\n"
143" start an NBD server for exporting block nodes\n"
144"\n"
145" --object help list object types that can be added\n"
146" --object <type>,help list properties for the given object type\n"
147" --object <type>[,<property>=<value>...]\n"
148" create a new object of type <type>, setting\n"
149" properties in the order they are specified. Note\n"
150" that the 'id' property must be set.\n"
151" See the qemu(1) man page for documentation of the\n"
152" objects that can be added.\n"
153"\n"
154" --pidfile <path> write process ID to a file after startup\n"
155"\n"
156QEMU_HELP_BOTTOM "\n",
157 g_get_prgname());
158}
159
160enum {
161 OPTION_BLOCKDEV = 256,
162 OPTION_CHARDEV,
163 OPTION_DAEMONIZE,
164 OPTION_EXPORT,
165 OPTION_MONITOR,
166 OPTION_NBD_SERVER,
167 OPTION_OBJECT,
168 OPTION_PIDFILE,
169};
170
171extern QemuOptsList qemu_chardev_opts;
172
173static void init_qmp_commands(void)
174{
175 qmp_init_marshal(&qmp_commands);
176
177 QTAILQ_INIT(&qmp_cap_negotiation_commands);
178 qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
179 qmp_marshal_qmp_capabilities,
180 QCO_ALLOW_PRECONFIG, 0);
181}
182
183static int getopt_set_loc(int argc, char **argv, const char *optstring,
184 const struct option *longopts)
185{
186 int c, save_index;
187
188 optarg = NULL;
189 save_index = optind;
190 c = getopt_long(argc, argv, optstring, longopts, NULL);
191 if (optarg) {
192 loc_set_cmdline(argv, save_index, MAX(1, optind - save_index));
193 }
194 return c;
195}
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213static void process_options(int argc, char *argv[], bool pre_init_pass)
214{
215 int c;
216
217 static const struct option long_options[] = {
218 {"blockdev", required_argument, NULL, OPTION_BLOCKDEV},
219 {"chardev", required_argument, NULL, OPTION_CHARDEV},
220 {"daemonize", no_argument, NULL, OPTION_DAEMONIZE},
221 {"export", required_argument, NULL, OPTION_EXPORT},
222 {"help", no_argument, NULL, 'h'},
223 {"monitor", required_argument, NULL, OPTION_MONITOR},
224 {"nbd-server", required_argument, NULL, OPTION_NBD_SERVER},
225 {"object", required_argument, NULL, OPTION_OBJECT},
226 {"pidfile", required_argument, NULL, OPTION_PIDFILE},
227 {"trace", required_argument, NULL, 'T'},
228 {"version", no_argument, NULL, 'V'},
229 {0, 0, 0, 0}
230 };
231
232
233
234
235
236
237 optind = 1;
238 while ((c = getopt_set_loc(argc, argv, "-hT:V", long_options)) != -1) {
239 bool handle_option_pre_init;
240
241
242 handle_option_pre_init =
243 c == '?' ||
244 c == 'h' ||
245 c == 'V' ||
246 c == OPTION_DAEMONIZE ||
247 c == OPTION_PIDFILE;
248
249
250 if (pre_init_pass != handle_option_pre_init) {
251 continue;
252 }
253
254 switch (c) {
255 case '?':
256 exit(EXIT_FAILURE);
257 case 'h':
258 help();
259 exit(EXIT_SUCCESS);
260 case 'T':
261 trace_opt_parse(optarg);
262 trace_init_file();
263 break;
264 case 'V':
265 printf("qemu-storage-daemon version "
266 QEMU_FULL_VERSION "\n" QEMU_COPYRIGHT "\n");
267 exit(EXIT_SUCCESS);
268 case OPTION_BLOCKDEV:
269 {
270 Visitor *v;
271 BlockdevOptions *options;
272
273 v = qobject_input_visitor_new_str(optarg, "driver",
274 &error_fatal);
275
276 visit_type_BlockdevOptions(v, NULL, &options, &error_fatal);
277 visit_free(v);
278
279 qmp_blockdev_add(options, &error_fatal);
280 qapi_free_BlockdevOptions(options);
281 break;
282 }
283 case OPTION_CHARDEV:
284 {
285
286 QemuOpts *opts = qemu_opts_parse_noisily(&qemu_chardev_opts,
287 optarg, true);
288 if (opts == NULL) {
289 exit(EXIT_FAILURE);
290 }
291
292 if (!qemu_chr_new_from_opts(opts, NULL, &error_fatal)) {
293
294 exit(EXIT_SUCCESS);
295 }
296 qemu_opts_del(opts);
297 break;
298 }
299 case OPTION_DAEMONIZE:
300 if (os_set_daemonize(true) < 0) {
301
302
303
304
305 fprintf(stderr, "--daemonize not supported in this build\n");
306 exit(EXIT_FAILURE);
307 }
308 break;
309 case OPTION_EXPORT:
310 {
311 Visitor *v;
312 BlockExportOptions *export;
313
314 v = qobject_input_visitor_new_str(optarg, "type", &error_fatal);
315 visit_type_BlockExportOptions(v, NULL, &export, &error_fatal);
316 visit_free(v);
317
318 qmp_block_export_add(export, &error_fatal);
319 qapi_free_BlockExportOptions(export);
320 break;
321 }
322 case OPTION_MONITOR:
323 {
324 Visitor *v;
325 MonitorOptions *monitor;
326
327 v = qobject_input_visitor_new_str(optarg, "chardev",
328 &error_fatal);
329 visit_type_MonitorOptions(v, NULL, &monitor, &error_fatal);
330 visit_free(v);
331
332
333 monitor_init(monitor, false, &error_fatal);
334 qapi_free_MonitorOptions(monitor);
335 break;
336 }
337 case OPTION_NBD_SERVER:
338 {
339 Visitor *v;
340 NbdServerOptions *options;
341
342 v = qobject_input_visitor_new_str(optarg, NULL, &error_fatal);
343 visit_type_NbdServerOptions(v, NULL, &options, &error_fatal);
344 visit_free(v);
345
346 nbd_server_start_options(options, &error_fatal);
347 qapi_free_NbdServerOptions(options);
348 break;
349 }
350 case OPTION_OBJECT:
351 user_creatable_process_cmdline(optarg);
352 break;
353 case OPTION_PIDFILE:
354 pid_file = optarg;
355 break;
356 case 1:
357 error_report("Unexpected argument");
358 exit(EXIT_FAILURE);
359 default:
360 g_assert_not_reached();
361 }
362 }
363 loc_set_none();
364}
365
366static void pid_file_cleanup(void)
367{
368 unlink(pid_file_realpath);
369}
370
371static void pid_file_init(void)
372{
373 Error *err = NULL;
374
375 if (!pid_file) {
376 return;
377 }
378
379 if (!qemu_write_pidfile(pid_file, &err)) {
380 error_reportf_err(err, "cannot create PID file: ");
381 exit(EXIT_FAILURE);
382 }
383
384 pid_file_realpath = g_malloc(PATH_MAX);
385 if (!realpath(pid_file, pid_file_realpath)) {
386 error_report("cannot resolve PID file path: %s: %s",
387 pid_file, strerror(errno));
388 unlink(pid_file);
389 exit(EXIT_FAILURE);
390 }
391
392 atexit(pid_file_cleanup);
393}
394
395int main(int argc, char *argv[])
396{
397#ifdef CONFIG_POSIX
398 signal(SIGPIPE, SIG_IGN);
399#endif
400
401 error_init(argv[0]);
402 qemu_init_exec_dir(argv[0]);
403 os_setup_signal_handling();
404
405 process_options(argc, argv, true);
406
407 os_daemonize();
408
409 module_call_init(MODULE_INIT_QOM);
410 module_call_init(MODULE_INIT_TRACE);
411 qemu_add_opts(&qemu_trace_opts);
412 qcrypto_init(&error_fatal);
413 bdrv_init();
414 monitor_init_globals();
415 init_qmp_commands();
416
417 if (!trace_init_backends()) {
418 return EXIT_FAILURE;
419 }
420 qemu_set_log(LOG_TRACE, &error_fatal);
421
422 qemu_init_main_loop(&error_fatal);
423 process_options(argc, argv, false);
424
425
426
427
428
429
430 pid_file_init();
431 os_setup_post();
432
433 while (!exit_requested) {
434 main_loop_wait(false);
435 }
436
437 blk_exp_close_all();
438 bdrv_drain_all_begin();
439 job_cancel_sync_all();
440 bdrv_close_all();
441
442 monitor_cleanup();
443 qemu_chr_cleanup();
444 user_creatable_cleanup();
445
446 return EXIT_SUCCESS;
447}
448