#include "monitor/monitor-internal.h"
#include "qapi/error.h"
-#include "qapi/qapi-visit-block.h"
#include "qapi/qapi-visit-block-core.h"
+#include "qapi/qapi-visit-block-export.h"
#include "qapi/qapi-visit-control.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h"
#include "sysemu/runstate.h"
#include "trace/control.h"
+static const char *pid_file;
static volatile bool exit_requested = false;
void qemu_system_killed(int signal, pid_t pid)
" --chardev <options> configure a character device backend\n"
" (see the qemu(1) man page for possible options)\n"
"\n"
-" --export [type=]nbd,device=<node-name>[,name=<export-name>]\n"
+" --export [type=]nbd,id=<id>,node-name=<node-name>[,name=<export-name>]\n"
" [,writable=on|off][,bitmap=<name>]\n"
" export the specified block node over NBD\n"
" (requires --nbd-server)\n"
"\n"
+#ifdef CONFIG_FUSE
+" --export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>\n"
+" [,growable=on|off][,writable=on|off]\n"
+" export the specified block node over FUSE\n"
+"\n"
+#endif /* CONFIG_FUSE */
" --monitor [chardev=]name[,mode=control][,pretty[=on|off]]\n"
" configure a QMP monitor\n"
"\n"
" --nbd-server addr.type=inet,addr.host=<host>,addr.port=<port>\n"
-" [,tls-creds=<id>][,tls-authz=<id>]\n"
+" [,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]\n"
" --nbd-server addr.type=unix,addr.path=<path>\n"
-" [,tls-creds=<id>][,tls-authz=<id>]\n"
+" [,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]\n"
" start an NBD server for exporting block nodes\n"
"\n"
" --object help list object types that can be added\n"
" See the qemu(1) man page for documentation of the\n"
" objects that can be added.\n"
"\n"
+" --pidfile <path> write process ID to a file after startup\n"
+"\n"
QEMU_HELP_BOTTOM "\n",
error_get_progname());
}
OPTION_MONITOR,
OPTION_NBD_SERVER,
OPTION_OBJECT,
+ OPTION_PIDFILE,
};
extern QemuOptsList qemu_chardev_opts;
-static QemuOptsList qemu_object_opts = {
- .name = "object",
- .implied_opt_name = "qom-type",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
- .desc = {
- { }
- },
-};
-
static void init_qmp_commands(void)
{
qmp_init_marshal(&qmp_commands);
- qmp_register_command(&qmp_commands, "query-qmp-schema",
- qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
QTAILQ_INIT(&qmp_cap_negotiation_commands);
qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG);
}
-static void init_export(BlockExport *export, Error **errp)
+static int getopt_set_loc(int argc, char **argv, const char *optstring,
+ const struct option *longopts)
{
- switch (export->type) {
- case BLOCK_EXPORT_TYPE_NBD:
- qmp_nbd_server_add(&export->u.nbd, errp);
- break;
- default:
- g_assert_not_reached();
+ int c, save_index;
+
+ optarg = NULL;
+ save_index = optind;
+ c = getopt_long(argc, argv, optstring, longopts, NULL);
+ if (optarg) {
+ loc_set_cmdline(argv, save_index, MAX(1, optind - save_index));
}
+ return c;
}
static void process_options(int argc, char *argv[])
{"monitor", required_argument, NULL, OPTION_MONITOR},
{"nbd-server", required_argument, NULL, OPTION_NBD_SERVER},
{"object", required_argument, NULL, OPTION_OBJECT},
+ {"pidfile", required_argument, NULL, OPTION_PIDFILE},
{"trace", required_argument, NULL, 'T'},
{"version", no_argument, NULL, 'V'},
{0, 0, 0, 0}
* they are given on the command lines. This means that things must be
* defined first before they can be referenced in another option.
*/
- while ((c = getopt_long(argc, argv, "hT:V", long_options, NULL)) != -1) {
+ while ((c = getopt_set_loc(argc, argv, "-hT:V", long_options)) != -1) {
switch (c) {
case '?':
exit(EXIT_FAILURE);
help();
exit(EXIT_SUCCESS);
case 'T':
- {
- char *trace_file = trace_opt_parse(optarg);
- trace_init_file(trace_file);
- g_free(trace_file);
- break;
- }
+ trace_opt_parse(optarg);
+ trace_init_file();
+ break;
case 'V':
printf("qemu-storage-daemon version "
QEMU_FULL_VERSION "\n" QEMU_COPYRIGHT "\n");
case OPTION_EXPORT:
{
Visitor *v;
- BlockExport *export;
+ BlockExportOptions *export;
v = qobject_input_visitor_new_str(optarg, "type", &error_fatal);
- visit_type_BlockExport(v, NULL, &export, &error_fatal);
+ visit_type_BlockExportOptions(v, NULL, &export, &error_fatal);
visit_free(v);
- init_export(export, &error_fatal);
- qapi_free_BlockExport(export);
+ qmp_block_export_add(export, &error_fatal);
+ qapi_free_BlockExportOptions(export);
break;
}
case OPTION_MONITOR:
break;
}
case OPTION_OBJECT:
- {
- QemuOpts *opts;
- const char *type;
- QDict *args;
-
- /* FIXME The keyval parser rejects 'help' arguments, so we must
- * unconditionall try QemuOpts first. */
- opts = qemu_opts_parse(&qemu_object_opts,
- optarg, true, &error_fatal);
- type = qemu_opt_get(opts, "qom-type");
- if (type && user_creatable_print_help(type, opts)) {
- exit(EXIT_SUCCESS);
- }
- qemu_opts_del(opts);
-
- args = keyval_parse(optarg, "qom-type", &error_fatal);
- user_creatable_add_dict(args, true, &error_fatal);
- qobject_unref(args);
- break;
- }
+ user_creatable_process_cmdline(optarg);
+ break;
+ case OPTION_PIDFILE:
+ pid_file = optarg;
+ break;
+ case 1:
+ error_report("Unexpected argument");
+ exit(EXIT_FAILURE);
default:
g_assert_not_reached();
}
}
- if (optind != argc) {
- error_report("Unexpected argument: %s", argv[optind]);
+ loc_set_none();
+}
+
+static void pid_file_cleanup(void)
+{
+ unlink(pid_file);
+}
+
+static void pid_file_init(void)
+{
+ Error *err = NULL;
+
+ if (!pid_file) {
+ return;
+ }
+
+ if (!qemu_write_pidfile(pid_file, &err)) {
+ error_reportf_err(err, "cannot create PID file: ");
exit(EXIT_FAILURE);
}
+
+ atexit(pid_file_cleanup);
}
int main(int argc, char *argv[])
module_call_init(MODULE_INIT_QOM);
module_call_init(MODULE_INIT_TRACE);
- qemu_add_opts(&qemu_object_opts);
qemu_add_opts(&qemu_trace_opts);
qcrypto_init(&error_fatal);
bdrv_init();
qemu_init_main_loop(&error_fatal);
process_options(argc, argv);
+ /*
+ * Write the pid file after creating chardevs, exports, and NBD servers but
+ * before accepting connections. This ordering is documented. Do not change
+ * it.
+ */
+ pid_file_init();
+
while (!exit_requested) {
main_loop_wait(false);
}
+ blk_exp_close_all();
+ bdrv_drain_all_begin();
+ job_cancel_sync_all();
+ bdrv_close_all();
+
monitor_cleanup();
qemu_chr_cleanup();
user_creatable_cleanup();