#define MBR_SIZE 512
-static SocketAddress *saddr;
static int persistent = 0;
static enum { RUNNING, TERMINATE, TERMINATED } state;
static int shared = 1;
struct NbdClientOpts {
char *device;
char *srcpath;
+ SocketAddress *saddr;
+ int old_stderr;
bool fork_process;
bool verbose;
};
+static void nbd_client_release_pipe(int old_stderr)
+{
+ /* Close stderr so that the qemu-nbd process exits. */
+ if (dup2(old_stderr, STDERR_FILENO) < 0) {
+ error_report("Could not release pipe to parent: %s",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ if (old_stderr != STDOUT_FILENO && close(old_stderr) < 0) {
+ error_report("Could not release qemu-nbd: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+}
+
#if HAVE_NBD_DEVICE
static void *show_parts(void *arg)
{
static void *nbd_client_thread(void *arg)
{
struct NbdClientOpts *opts = arg;
- NBDExportInfo info = { .request_sizes = false, .name = g_strdup("") };
+ /* TODO: Revisit this if nbd.ko ever gains support for structured reply */
+ NBDExportInfo info = { .request_sizes = false, .name = g_strdup(""),
+ .mode = NBD_MODE_SIMPLE };
QIOChannelSocket *sioc;
int fd = -1;
int ret = EXIT_FAILURE;
sioc = qio_channel_socket_new();
if (qio_channel_socket_connect_sync(sioc,
- saddr,
+ opts->saddr,
&local_error) < 0) {
error_report_err(local_error);
goto out;
fprintf(stderr, "NBD device %s is now connected to %s\n",
opts->device, opts->srcpath);
} else {
- /* Close stderr so that the qemu-nbd process exits. */
- if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) {
- error_report("Could not release pipe to parent: %s",
- strerror(errno));
- exit(EXIT_FAILURE);
- }
+ nbd_client_release_pipe(opts->old_stderr);
}
if (nbd_client(fd) < 0) {
.verbose = false,
.device = NULL,
.srcpath = NULL,
+ .saddr = NULL,
+ .old_stderr = STDOUT_FILENO,
};
#ifdef CONFIG_POSIX
}
if (list) {
- saddr = nbd_build_socket_address(sockpath, bindto, port);
- return qemu_nbd_client_list(saddr, tlscreds,
+ opts.saddr = nbd_build_socket_address(sockpath, bindto, port);
+ return qemu_nbd_client_list(opts.saddr, tlscreds,
tlshostname ? tlshostname : bindto);
}
g_autoptr(GError) err = NULL;
int stderr_fd[2];
pid_t pid;
- int ret;
if (!g_unix_open_pipe(stderr_fd, FD_CLOEXEC, &err)) {
error_report("Error setting up communication pipe: %s",
close(stderr_fd[0]);
+ /* Remember parent's stderr if we will be restoring it. */
+ if (opts.verbose /* fork_process is set */) {
+ opts.old_stderr = dup(STDERR_FILENO);
+ if (opts.old_stderr < 0) {
+ error_report("Could not dup original stderr: %s",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
ret = qemu_daemon(1, 0);
saved_errno = errno; /* dup2 will overwrite error below */
exit(EXIT_FAILURE);
}
#endif
- saddr = nbd_build_socket_address(sockpath, bindto, port);
- if (qio_net_listener_open_sync(server, saddr, backlog,
+ opts.saddr = nbd_build_socket_address(sockpath, bindto, port);
+ if (qio_net_listener_open_sync(server, opts.saddr, backlog,
&local_err) < 0) {
object_unref(OBJECT(server));
error_report_err(local_err);
if (opts.device) {
#if HAVE_NBD_DEVICE
- int ret;
ret = pthread_create(&client_thread, NULL, nbd_client_thread, &opts);
if (ret != 0) {
error_report("Failed to create client thread: %s", strerror(ret));
}
if (opts.fork_process) {
- if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) {
- error_report("Could not release pipe to parent: %s",
- strerror(errno));
- exit(EXIT_FAILURE);
- }
+ nbd_client_release_pipe(opts.old_stderr);
}
state = RUNNING;
qemu_opts_del(sn_opts);
if (opts.device) {
- void *ret;
- pthread_join(client_thread, &ret);
- exit(ret != NULL);
+ void *result;
+ pthread_join(client_thread, &result);
+ ret = (intptr_t)result;
+ exit(ret);
} else {
exit(EXIT_SUCCESS);
}