#include "qemu/config-file.h"
#include "qemu/bswap.h"
#include "qemu/log.h"
+#include "qemu/systemd.h"
#include "block/snapshot.h"
#include "qapi/util.h"
#include "qapi/qmp/qstring.h"
goto out_socket;
}
- ret = nbd_init(fd, sioc, nbdflags, size);
+ ret = nbd_init(fd, sioc, nbdflags, size, &local_error);
if (ret < 0) {
+ error_report_err(local_error);
goto out_fd;
}
static int nbd_can_accept(void)
{
- return nb_fds < shared;
+ return state == RUNNING && nb_fds < shared;
}
static void nbd_export_closed(NBDExport *exp)
static void nbd_update_server_watch(void);
-static void nbd_client_closed(NBDClient *client)
+static void nbd_client_closed(NBDClient *client, bool negotiated)
{
nb_fds--;
- if (nb_fds == 0 && !persistent && state == RUNNING) {
+ if (negotiated && nb_fds == 0 && !persistent && state == RUNNING) {
state = TERMINATE;
}
nbd_update_server_watch();
saddr = g_new0(SocketAddress, 1);
if (sockpath) {
- saddr->type = SOCKET_ADDRESS_KIND_UNIX;
- saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
- saddr->u.q_unix.data->path = g_strdup(sockpath);
+ saddr->type = SOCKET_ADDRESS_TYPE_UNIX;
+ saddr->u.q_unix.path = g_strdup(sockpath);
} else {
InetSocketAddress *inet;
- saddr->type = SOCKET_ADDRESS_KIND_INET;
- inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1);
+ saddr->type = SOCKET_ADDRESS_TYPE_INET;
+ inet = &saddr->u.inet;
inet->host = g_strdup(bindto);
if (port) {
inet->port = g_strdup(port);
return creds;
}
+static void setup_address_and_port(const char **address, const char **port)
+{
+ if (*address == NULL) {
+ *address = "0.0.0.0";
+ }
+
+ if (*port == NULL) {
+ *port = stringify(NBD_DEFAULT_PORT);
+ }
+}
+
+/*
+ * Check socket parameters compatibility when socket activation is used.
+ */
+static const char *socket_activation_validate_opts(const char *device,
+ const char *sockpath,
+ const char *address,
+ const char *port)
+{
+ if (device != NULL) {
+ return "NBD device can't be set when using socket activation";
+ }
+
+ if (sockpath != NULL) {
+ return "Unix socket can't be set when using socket activation";
+ }
+
+ if (address != NULL) {
+ return "The interface can't be set when using socket activation";
+ }
+
+ if (port != NULL) {
+ return "TCP port number can't be set when using socket activation";
+ }
+
+ return NULL;
+}
int main(int argc, char **argv)
{
off_t dev_offset = 0;
uint16_t nbdflags = 0;
bool disconnect = false;
- const char *bindto = "0.0.0.0";
+ const char *bindto = NULL;
const char *port = NULL;
char *sockpath = NULL;
char *device = NULL;
char *trace_file = NULL;
bool fork_process = false;
int old_stderr = -1;
+ unsigned socket_activation;
/* The client thread uses SIGTERM to interrupt the server. A signal
* handler ensures that "qemu-nbd -v -c" exits with a nice status code.
sa_sigterm.sa_handler = termsig_handler;
sigaction(SIGTERM, &sa_sigterm, NULL);
+#ifdef CONFIG_POSIX
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
module_call_init(MODULE_INIT_TRACE);
qcrypto_init(&error_fatal);
trace_init_file(trace_file);
qemu_set_log(LOG_TRACE);
+ socket_activation = check_socket_activation();
+ if (socket_activation == 0) {
+ setup_address_and_port(&bindto, &port);
+ } else {
+ /* Using socket activation - check user didn't use -p etc. */
+ const char *err_msg = socket_activation_validate_opts(device, sockpath,
+ bindto, port);
+ if (err_msg != NULL) {
+ error_report("%s", err_msg);
+ exit(EXIT_FAILURE);
+ }
+
+ /* qemu-nbd can only listen on a single socket. */
+ if (socket_activation > 1) {
+ error_report("qemu-nbd does not support socket activation with %s > 1",
+ "LISTEN_FDS");
+ exit(EXIT_FAILURE);
+ }
+ }
+
if (tlscredsid) {
if (sockpath) {
error_report("TLS is only supported with IPv4/IPv6");
snprintf(sockpath, 128, SOCKET_PATH, basename(device));
}
- saddr = nbd_build_socket_address(sockpath, bindto, port);
+ if (socket_activation == 0) {
+ server_ioc = qio_channel_socket_new();
+ saddr = nbd_build_socket_address(sockpath, bindto, port);
+ if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) {
+ object_unref(OBJECT(server_ioc));
+ error_report_err(local_err);
+ return 1;
+ }
+ } else {
+ /* See comment in check_socket_activation above. */
+ assert(socket_activation == 1);
+ server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD,
+ &local_err);
+ if (server_ioc == NULL) {
+ error_report("Failed to use socket activation: %s",
+ error_get_pretty(local_err));
+ exit(EXIT_FAILURE);
+ }
+ }
if (qemu_init_main_loop(&local_err)) {
error_report_err(local_err);
} else {
if (fmt) {
options = qdict_new();
- qdict_put(options, "driver", qstring_from_str(fmt));
+ qdict_put_str(options, "driver", fmt);
}
blk = blk_new_open(srcpath, NULL, options, flags, &local_err);
}
exit(EXIT_FAILURE);
}
- server_ioc = qio_channel_socket_new();
- if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) {
- object_unref(OBJECT(server_ioc));
- error_report_err(local_err);
- return 1;
- }
-
if (device) {
int ret;