qemu-nbd.c 28.8 KB
Newer Older
1
/*
B
bellard 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15
 *  Copyright (C) 2005  Anthony Liguori <anthony@codemonkey.ws>
 *
 *  Network Block Device
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; under version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
B
bellard 已提交
17 18
 */

P
Peter Maydell 已提交
19
#include "qemu/osdep.h"
20
#include "qapi/error.h"
21
#include "qemu-common.h"
22
#include "qemu/cutils.h"
M
Markus Armbruster 已提交
23
#include "sysemu/block-backend.h"
24
#include "block/block_int.h"
25
#include "block/nbd.h"
26
#include "qemu/main-loop.h"
27
#include "qemu/error-report.h"
28
#include "qemu/config-file.h"
29
#include "qemu/bswap.h"
30
#include "block/snapshot.h"
31
#include "qapi/util.h"
32
#include "qapi/qmp/qstring.h"
33
#include "qom/object_interfaces.h"
34
#include "io/channel-socket.h"
35
#include "crypto/init.h"
B
bellard 已提交
36 37

#include <getopt.h>
38
#include <libgen.h>
P
Paolo Bonzini 已提交
39
#include <pthread.h>
40

41
#define SOCKET_PATH                "/var/lock/qemu-nbd-%s"
42 43 44 45 46 47 48
#define QEMU_NBD_OPT_CACHE         256
#define QEMU_NBD_OPT_AIO           257
#define QEMU_NBD_OPT_DISCARD       258
#define QEMU_NBD_OPT_DETECT_ZEROES 259
#define QEMU_NBD_OPT_OBJECT        260
#define QEMU_NBD_OPT_TLSCREDS      261
#define QEMU_NBD_OPT_IMAGE_OPTS    262
B
bellard 已提交
49

50 51
#define MBR_SIZE 512

P
Paolo Bonzini 已提交
52
static NBDExport *exp;
53
static bool newproto;
54
static int verbose;
P
Paolo Bonzini 已提交
55
static char *srcpath;
56
static SocketAddress *saddr;
57 58
static int persistent = 0;
static enum { RUNNING, TERMINATE, TERMINATING, TERMINATED } state;
P
Paolo Bonzini 已提交
59 60
static int shared = 1;
static int nb_fds;
61 62
static QIOChannelSocket *server_ioc;
static int server_watch = -1;
63
static QCryptoTLSCreds *tlscreds;
B
bellard 已提交
64 65 66

static void usage(const char *name)
{
67
    (printf) (
B
bellard 已提交
68 69 70
"Usage: %s [OPTIONS] FILE\n"
"QEMU Disk Network Block Device Server\n"
"\n"
71 72
"  -h, --help                display this help and exit\n"
"  -V, --version             output version information and exit\n"
73 74
"\n"
"Connection properties:\n"
75 76 77 78 79 80 81
"  -p, --port=PORT           port to listen on (default `%d')\n"
"  -b, --bind=IFACE          interface to bind to (default `0.0.0.0')\n"
"  -k, --socket=PATH         path to the unix socket\n"
"                            (default '"SOCKET_PATH"')\n"
"  -e, --shared=NUM          device can be shared by NUM clients (default '1')\n"
"  -t, --persistent          don't exit on the last connection\n"
"  -v, --verbose             display extra debugging information\n"
E
Eric Blake 已提交
82
"  -x, --export-name=NAME    expose export by name\n"
B
bellard 已提交
83
"\n"
84
"Exposing part of the image:\n"
85 86
"  -o, --offset=OFFSET       offset into the image\n"
"  -P, --partition=NUM       only expose partition NUM\n"
87
"\n"
88 89 90
"General purpose options:\n"
"  --object type,id=ID,...   define an object such as 'secret' for providing\n"
"                            passwords and/or encryption keys\n"
91 92
#ifdef __linux__
"Kernel NBD client support:\n"
93 94
"  -c, --connect=DEV         connect FILE to the local NBD device DEV\n"
"  -d, --disconnect          disconnect the specified device\n"
95 96 97 98
"\n"
#endif
"\n"
"Block device options:\n"
99 100 101 102 103
"  -f, --format=FORMAT       set image format (raw, qcow2, ...)\n"
"  -r, --read-only           export read-only\n"
"  -s, --snapshot            use FILE as an external snapshot, create a temporary\n"
"                            file with backing_file=FILE, redirect the write to\n"
"                            the temporary one\n"
104
"  -l, --load-snapshot=SNAPSHOT_PARAM\n"
105 106 107 108 109 110 111
"                            load an internal snapshot inside FILE and export it\n"
"                            as an read-only device, SNAPSHOT_PARAM format is\n"
"                            'snapshot.id=[ID],snapshot.name=[NAME]', or\n"
"                            '[ID_OR_NAME]'\n"
"  -n, --nocache             disable host cache\n"
"      --cache=MODE          set cache mode (none, writeback, ...)\n"
"      --aio=MODE            set AIO mode (native or threads)\n"
112
"      --discard=MODE        set discard mode (ignore, unmap)\n"
113
"      --detect-zeroes=MODE  set detect-zeroes mode (off, on, unmap)\n"
114
"      --image-opts          treat FILE as a full set of image options\n"
115 116
"\n"
"Report bugs to <qemu-devel@nongnu.org>\n"
117
    , name, NBD_DEFAULT_PORT, "DEVICE");
B
bellard 已提交
118 119 120 121 122
}

static void version(const char *name)
{
    printf(
123
"%s version 0.0.1\n"
B
bellard 已提交
124 125 126 127 128
"Written by Anthony Liguori.\n"
"\n"
"Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>.\n"
"This is free software; see the source for copying conditions.  There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
129
    , name);
B
bellard 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
}

struct partition_record
{
    uint8_t bootable;
    uint8_t start_head;
    uint32_t start_cylinder;
    uint8_t start_sector;
    uint8_t system;
    uint8_t end_head;
    uint8_t end_cylinder;
    uint8_t end_sector;
    uint32_t start_sector_abs;
    uint32_t nb_sectors_abs;
};

static void read_partition(uint8_t *p, struct partition_record *r)
{
    r->bootable = p[0];
    r->start_head = p[1];
    r->start_cylinder = p[3] | ((p[2] << 2) & 0x0300);
    r->start_sector = p[2] & 0x3f;
    r->system = p[4];
    r->end_head = p[5];
    r->end_cylinder = p[7] | ((p[6] << 2) & 0x300);
    r->end_sector = p[6] & 0x3f;
156 157 158

    r->start_sector_abs = le32_to_cpup((uint32_t *)(p +  8));
    r->nb_sectors_abs   = le32_to_cpup((uint32_t *)(p + 12));
B
bellard 已提交
159 160
}

161
static int find_partition(BlockBackend *blk, int partition,
B
bellard 已提交
162 163 164
                          off_t *offset, off_t *size)
{
    struct partition_record mbr[4];
165
    uint8_t data[MBR_SIZE];
B
bellard 已提交
166 167
    int i;
    int ext_partnum = 4;
R
Ryota Ozaki 已提交
168
    int ret;
B
bellard 已提交
169

170 171
    ret = blk_pread(blk, 0, data, sizeof(data));
    if (ret < 0) {
172
        error_report("error while reading: %s", strerror(-ret));
173
        exit(EXIT_FAILURE);
R
Ryota Ozaki 已提交
174
    }
B
bellard 已提交
175 176

    if (data[510] != 0x55 || data[511] != 0xaa) {
177
        return -EINVAL;
B
bellard 已提交
178 179 180 181 182
    }

    for (i = 0; i < 4; i++) {
        read_partition(&data[446 + 16 * i], &mbr[i]);

183
        if (!mbr[i].system || !mbr[i].nb_sectors_abs) {
B
bellard 已提交
184
            continue;
185
        }
B
bellard 已提交
186 187 188

        if (mbr[i].system == 0xF || mbr[i].system == 0x5) {
            struct partition_record ext[4];
189
            uint8_t data1[MBR_SIZE];
B
bellard 已提交
190 191
            int j;

192 193 194
            ret = blk_pread(blk, mbr[i].start_sector_abs * MBR_SIZE,
                            data1, sizeof(data1));
            if (ret < 0) {
195
                error_report("error while reading: %s", strerror(-ret));
196
                exit(EXIT_FAILURE);
R
Ryota Ozaki 已提交
197
            }
B
bellard 已提交
198 199 200

            for (j = 0; j < 4; j++) {
                read_partition(&data1[446 + 16 * j], &ext[j]);
201
                if (!ext[j].system || !ext[j].nb_sectors_abs) {
B
bellard 已提交
202
                    continue;
203
                }
B
bellard 已提交
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218

                if ((ext_partnum + j + 1) == partition) {
                    *offset = (uint64_t)ext[j].start_sector_abs << 9;
                    *size = (uint64_t)ext[j].nb_sectors_abs << 9;
                    return 0;
                }
            }
            ext_partnum += 4;
        } else if ((i + 1) == partition) {
            *offset = (uint64_t)mbr[i].start_sector_abs << 9;
            *size = (uint64_t)mbr[i].nb_sectors_abs << 9;
            return 0;
        }
    }

219
    return -ENOENT;
B
bellard 已提交
220 221
}

P
Paolo Bonzini 已提交
222 223
static void termsig_handler(int signum)
{
224
    atomic_cmpxchg(&state, RUNNING, TERMINATE);
P
Paolo Bonzini 已提交
225
    qemu_notify_event();
P
Paolo Bonzini 已提交
226 227
}

228

P
Paolo Bonzini 已提交
229
static void *show_parts(void *arg)
230
{
231
    char *device = arg;
P
Paolo Bonzini 已提交
232 233 234 235 236 237 238 239
    int nbd;

    /* linux just needs an open() to trigger
     * the partition table update
     * but remember to load the module with max_part != 0 :
     *     modprobe nbd max_part=63
     */
    nbd = open(device, O_RDWR);
240
    if (nbd >= 0) {
P
Paolo Bonzini 已提交
241 242 243 244
        close(nbd);
    }
    return NULL;
}
245

P
Paolo Bonzini 已提交
246 247
static void *nbd_client_thread(void *arg)
{
248
    char *device = arg;
P
Paolo Bonzini 已提交
249 250
    off_t size;
    uint32_t nbdflags;
251 252
    QIOChannelSocket *sioc;
    int fd;
P
Paolo Bonzini 已提交
253 254
    int ret;
    pthread_t show_parts_thread;
M
Max Reitz 已提交
255
    Error *local_error = NULL;
P
Paolo Bonzini 已提交
256

257 258 259 260
    sioc = qio_channel_socket_new();
    if (qio_channel_socket_connect_sync(sioc,
                                        saddr,
                                        &local_error) < 0) {
261
        error_report_err(local_error);
262 263
        goto out;
    }
P
Paolo Bonzini 已提交
264

265
    ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), NULL, &nbdflags,
266
                                NULL, NULL, NULL,
267
                                &size, &local_error);
268
    if (ret < 0) {
M
Max Reitz 已提交
269
        if (local_error) {
270
            error_report_err(local_error);
M
Max Reitz 已提交
271
        }
P
Paolo Bonzini 已提交
272
        goto out_socket;
P
Paolo Bonzini 已提交
273 274
    }

275
    fd = open(device, O_RDWR);
276
    if (fd < 0) {
277
        /* Linux-only, we can use %m in printf.  */
278
        error_report("Failed to open %s: %m", device);
P
Paolo Bonzini 已提交
279
        goto out_socket;
280 281
    }

282
    ret = nbd_init(fd, sioc, nbdflags, size);
283
    if (ret < 0) {
P
Paolo Bonzini 已提交
284
        goto out_fd;
P
Paolo Bonzini 已提交
285 286 287
    }

    /* update partition table */
288
    pthread_create(&show_parts_thread, NULL, show_parts, device);
P
Paolo Bonzini 已提交
289

290 291 292 293 294 295 296
    if (verbose) {
        fprintf(stderr, "NBD device %s is now connected to %s\n",
                device, srcpath);
    } else {
        /* Close stderr so that the qemu-nbd process exits.  */
        dup2(STDOUT_FILENO, STDERR_FILENO);
    }
P
Paolo Bonzini 已提交
297 298 299

    ret = nbd_client(fd);
    if (ret) {
P
Paolo Bonzini 已提交
300
        goto out_fd;
301
    }
P
Paolo Bonzini 已提交
302
    close(fd);
303
    object_unref(OBJECT(sioc));
P
Paolo Bonzini 已提交
304 305 306
    kill(getpid(), SIGTERM);
    return (void *) EXIT_SUCCESS;

P
Paolo Bonzini 已提交
307 308 309
out_fd:
    close(fd);
out_socket:
310
    object_unref(OBJECT(sioc));
P
Paolo Bonzini 已提交
311 312 313
out:
    kill(getpid(), SIGTERM);
    return (void *) EXIT_FAILURE;
314 315
}

316
static int nbd_can_accept(void)
P
Paolo Bonzini 已提交
317 318 319 320
{
    return nb_fds < shared;
}

321 322 323 324 325 326
static void nbd_export_closed(NBDExport *exp)
{
    assert(state == TERMINATING);
    state = TERMINATED;
}

327
static void nbd_update_server_watch(void);
328

329
static void nbd_client_closed(NBDClient *client)
P
Paolo Bonzini 已提交
330
{
331
    nb_fds--;
332 333 334
    if (nb_fds == 0 && !persistent && state == RUNNING) {
        state = TERMINATE;
    }
335
    nbd_update_server_watch();
336
    nbd_client_put(client);
P
Paolo Bonzini 已提交
337 338
}

339
static gboolean nbd_accept(QIOChannel *ioc, GIOCondition cond, gpointer opaque)
P
Paolo Bonzini 已提交
340
{
341
    QIOChannelSocket *cioc;
P
Paolo Bonzini 已提交
342

343 344 345 346
    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
                                     NULL);
    if (!cioc) {
        return TRUE;
P
Paolo Bonzini 已提交
347 348
    }

349
    if (state >= TERMINATE) {
350 351
        object_unref(OBJECT(cioc));
        return TRUE;
352 353
    }

354
    nb_fds++;
355
    nbd_update_server_watch();
356
    nbd_client_new(newproto ? NULL : exp, cioc,
357
                   tlscreds, NULL, nbd_client_closed);
358 359 360
    object_unref(OBJECT(cioc));

    return TRUE;
P
Paolo Bonzini 已提交
361 362
}

363
static void nbd_update_server_watch(void)
364 365
{
    if (nbd_can_accept()) {
366 367 368 369 370 371
        if (server_watch == -1) {
            server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc),
                                                 G_IO_IN,
                                                 nbd_accept,
                                                 NULL, NULL);
        }
372
    } else {
373 374 375 376
        if (server_watch != -1) {
            g_source_remove(server_watch);
            server_watch = -1;
        }
377 378 379
    }
}

380 381 382 383 384 385 386 387 388

static SocketAddress *nbd_build_socket_address(const char *sockpath,
                                               const char *bindto,
                                               const char *port)
{
    SocketAddress *saddr;

    saddr = g_new0(SocketAddress, 1);
    if (sockpath) {
389
        saddr->type = SOCKET_ADDRESS_KIND_UNIX;
390 391
        saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
        saddr->u.q_unix.data->path = g_strdup(sockpath);
392
    } else {
393
        InetSocketAddress *inet;
394
        saddr->type = SOCKET_ADDRESS_KIND_INET;
395
        inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1);
396
        inet->host = g_strdup(bindto);
397
        if (port) {
398
            inet->port = g_strdup(port);
399
        } else  {
400
            inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT);
401 402 403 404 405 406 407
        }
    }

    return saddr;
}


408 409 410 411 412 413 414 415 416 417
static QemuOptsList file_opts = {
    .name = "file",
    .implied_opt_name = "file",
    .head = QTAILQ_HEAD_INITIALIZER(file_opts.head),
    .desc = {
        /* no elements => accept any params */
        { /* end of list */ }
    },
};

418 419 420 421 422 423 424 425 426 427
static QemuOptsList qemu_object_opts = {
    .name = "object",
    .implied_opt_name = "qom-type",
    .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
    .desc = {
        { }
    },
};


428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458

static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
{
    Object *obj;
    QCryptoTLSCreds *creds;

    obj = object_resolve_path_component(
        object_get_objects_root(), id);
    if (!obj) {
        error_setg(errp, "No TLS credentials with id '%s'",
                   id);
        return NULL;
    }
    creds = (QCryptoTLSCreds *)
        object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS);
    if (!creds) {
        error_setg(errp, "Object with id '%s' is not TLS credentials",
                   id);
        return NULL;
    }

    if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
        error_setg(errp,
                   "Expecting TLS credentials with a server endpoint");
        return NULL;
    }
    object_ref(obj);
    return creds;
}


B
bellard 已提交
459 460
int main(int argc, char **argv)
{
M
Markus Armbruster 已提交
461
    BlockBackend *blk;
B
bellard 已提交
462 463
    BlockDriverState *bs;
    off_t dev_offset = 0;
P
Paolo Bonzini 已提交
464
    uint32_t nbdflags = 0;
465
    bool disconnect = false;
B
bellard 已提交
466
    const char *bindto = "0.0.0.0";
467 468
    const char *port = NULL;
    char *sockpath = NULL;
469
    char *device = NULL;
B
bellard 已提交
470
    off_t fd_size;
471 472
    QemuOpts *sn_opts = NULL;
    const char *sn_id_or_name = NULL;
473
    const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:";
B
bellard 已提交
474
    struct option lopt[] = {
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
        { "help", no_argument, NULL, 'h' },
        { "version", no_argument, NULL, 'V' },
        { "bind", required_argument, NULL, 'b' },
        { "port", required_argument, NULL, 'p' },
        { "socket", required_argument, NULL, 'k' },
        { "offset", required_argument, NULL, 'o' },
        { "read-only", no_argument, NULL, 'r' },
        { "partition", required_argument, NULL, 'P' },
        { "connect", required_argument, NULL, 'c' },
        { "disconnect", no_argument, NULL, 'd' },
        { "snapshot", no_argument, NULL, 's' },
        { "load-snapshot", required_argument, NULL, 'l' },
        { "nocache", no_argument, NULL, 'n' },
        { "cache", required_argument, NULL, QEMU_NBD_OPT_CACHE },
        { "aio", required_argument, NULL, QEMU_NBD_OPT_AIO },
        { "discard", required_argument, NULL, QEMU_NBD_OPT_DISCARD },
        { "detect-zeroes", required_argument, NULL,
          QEMU_NBD_OPT_DETECT_ZEROES },
        { "shared", required_argument, NULL, 'e' },
        { "format", required_argument, NULL, 'f' },
        { "persistent", no_argument, NULL, 't' },
        { "verbose", no_argument, NULL, 'v' },
        { "object", required_argument, NULL, QEMU_NBD_OPT_OBJECT },
        { "export-name", required_argument, NULL, 'x' },
        { "tls-creds", required_argument, NULL, QEMU_NBD_OPT_TLSCREDS },
        { "image-opts", no_argument, NULL, QEMU_NBD_OPT_IMAGE_OPTS },
501
        { NULL, 0, NULL, 0 }
B
bellard 已提交
502 503 504 505
    };
    int ch;
    int opt_ind = 0;
    char *end;
506
    int flags = BDRV_O_RDWR;
B
bellard 已提交
507
    int partition = -1;
508
    int ret = 0;
509
    bool seen_cache = false;
P
Paolo Bonzini 已提交
510
    bool seen_discard = false;
511
    bool seen_aio = false;
P
Paolo Bonzini 已提交
512
    pthread_t client_thread;
513
    const char *fmt = NULL;
514
    Error *local_err = NULL;
515
    BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
516
    QDict *options = NULL;
517
    const char *export_name = NULL;
518
    const char *tlscredsid = NULL;
519
    bool imageOpts = false;
520
    bool writethrough = true;
B
bellard 已提交
521

P
Paolo Bonzini 已提交
522 523 524
    /* The client thread uses SIGTERM to interrupt the server.  A signal
     * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
     */
P
Paolo Bonzini 已提交
525 526 527 528
    struct sigaction sa_sigterm;
    memset(&sa_sigterm, 0, sizeof(sa_sigterm));
    sa_sigterm.sa_handler = termsig_handler;
    sigaction(SIGTERM, &sa_sigterm, NULL);
529

530
    qcrypto_init(&error_fatal);
531

532 533
    module_call_init(MODULE_INIT_QOM);
    qemu_add_opts(&qemu_object_opts);
534
    qemu_init_exec_dir(argv[0]);
P
Paolo Bonzini 已提交
535

B
bellard 已提交
536 537 538
    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
        switch (ch) {
        case 's':
539 540 541
            flags |= BDRV_O_SNAPSHOT;
            break;
        case 'n':
542 543 544 545
            optarg = (char *) "none";
            /* fallthrough */
        case QEMU_NBD_OPT_CACHE:
            if (seen_cache) {
546 547
                error_report("-n and --cache can only be specified once");
                exit(EXIT_FAILURE);
548 549
            }
            seen_cache = true;
550
            if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) == -1) {
551 552
                error_report("Invalid cache mode `%s'", optarg);
                exit(EXIT_FAILURE);
553
            }
B
bellard 已提交
554
            break;
555 556
        case QEMU_NBD_OPT_AIO:
            if (seen_aio) {
557 558
                error_report("--aio can only be specified once");
                exit(EXIT_FAILURE);
559 560 561 562 563 564 565
            }
            seen_aio = true;
            if (!strcmp(optarg, "native")) {
                flags |= BDRV_O_NATIVE_AIO;
            } else if (!strcmp(optarg, "threads")) {
                /* this is the default */
            } else {
566 567
               error_report("invalid aio mode `%s'", optarg);
               exit(EXIT_FAILURE);
568 569
            }
            break;
P
Paolo Bonzini 已提交
570 571
        case QEMU_NBD_OPT_DISCARD:
            if (seen_discard) {
572 573
                error_report("--discard can only be specified once");
                exit(EXIT_FAILURE);
P
Paolo Bonzini 已提交
574 575 576
            }
            seen_discard = true;
            if (bdrv_parse_discard_flags(optarg, &flags) == -1) {
577 578
                error_report("Invalid discard mode `%s'", optarg);
                exit(EXIT_FAILURE);
P
Paolo Bonzini 已提交
579 580
            }
            break;
581 582 583 584
        case QEMU_NBD_OPT_DETECT_ZEROES:
            detect_zeroes =
                qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
                                optarg,
585
                                BLOCKDEV_DETECT_ZEROES_OPTIONS__MAX,
586 587 588
                                BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
                                &local_err);
            if (local_err) {
589 590
                error_reportf_err(local_err,
                                  "Failed to parse detect_zeroes mode: ");
591
                exit(EXIT_FAILURE);
592 593 594
            }
            if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
                !(flags & BDRV_O_UNMAP)) {
595 596 597
                error_report("setting detect-zeroes to unmap is not allowed "
                             "without setting discard operation to unmap");
                exit(EXIT_FAILURE);
598 599
            }
            break;
B
bellard 已提交
600 601 602 603
        case 'b':
            bindto = optarg;
            break;
        case 'p':
604
            port = optarg;
B
bellard 已提交
605 606 607 608
            break;
        case 'o':
                dev_offset = strtoll (optarg, &end, 0);
            if (*end) {
609 610
                error_report("Invalid offset `%s'", optarg);
                exit(EXIT_FAILURE);
B
bellard 已提交
611 612
            }
            if (dev_offset < 0) {
613 614
                error_report("Offset must be positive `%s'", optarg);
                exit(EXIT_FAILURE);
B
bellard 已提交
615 616
            }
            break;
617 618
        case 'l':
            if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
619 620
                sn_opts = qemu_opts_parse_noisily(&internal_snapshot_opts,
                                                  optarg, false);
621
                if (!sn_opts) {
622 623 624
                    error_report("Failed in parsing snapshot param `%s'",
                                 optarg);
                    exit(EXIT_FAILURE);
625 626 627 628 629
                }
            } else {
                sn_id_or_name = optarg;
            }
            /* fall through */
B
bellard 已提交
630
        case 'r':
P
Paolo Bonzini 已提交
631
            nbdflags |= NBD_FLAG_READ_ONLY;
N
Naphtali Sprei 已提交
632
            flags &= ~BDRV_O_RDWR;
B
bellard 已提交
633 634 635
            break;
        case 'P':
            partition = strtol(optarg, &end, 0);
636
            if (*end) {
637 638
                error_report("Invalid partition `%s'", optarg);
                exit(EXIT_FAILURE);
639 640
            }
            if (partition < 1 || partition > 8) {
641 642
                error_report("Invalid partition %d", partition);
                exit(EXIT_FAILURE);
643
            }
B
bellard 已提交
644
            break;
645
        case 'k':
P
Paolo Bonzini 已提交
646
            sockpath = optarg;
647
            if (sockpath[0] != '/') {
648
                error_report("socket path must be absolute");
649
                exit(EXIT_FAILURE);
650
            }
651 652 653 654 655 656 657
            break;
        case 'd':
            disconnect = true;
            break;
        case 'c':
            device = optarg;
            break;
658 659 660
        case 'e':
            shared = strtol(optarg, &end, 0);
            if (*end) {
661 662
                error_report("Invalid shared device number '%s'", optarg);
                exit(EXIT_FAILURE);
663 664
            }
            if (shared < 1) {
665
                error_report("Shared device number must be greater than 0");
666
                exit(EXIT_FAILURE);
667 668
            }
            break;
669 670 671
        case 'f':
            fmt = optarg;
            break;
672 673 674
        case 't':
            persistent = 1;
            break;
675 676 677
        case 'x':
            export_name = optarg;
            break;
B
bellard 已提交
678 679 680 681 682 683 684 685 686 687 688 689
        case 'v':
            verbose = 1;
            break;
        case 'V':
            version(argv[0]);
            exit(0);
            break;
        case 'h':
            usage(argv[0]);
            exit(0);
            break;
        case '?':
690 691
            error_report("Try `%s --help' for more information.", argv[0]);
            exit(EXIT_FAILURE);
692 693 694 695 696 697 698 699
        case QEMU_NBD_OPT_OBJECT: {
            QemuOpts *opts;
            opts = qemu_opts_parse_noisily(&qemu_object_opts,
                                           optarg, true);
            if (!opts) {
                exit(EXIT_FAILURE);
            }
        }   break;
700 701 702
        case QEMU_NBD_OPT_TLSCREDS:
            tlscredsid = optarg;
            break;
703 704 705
        case QEMU_NBD_OPT_IMAGE_OPTS:
            imageOpts = true;
            break;
B
bellard 已提交
706 707 708 709
        }
    }

    if ((argc - optind) != 1) {
710 711
        error_report("Invalid number of arguments");
        error_printf("Try `%s --help' for more information.\n", argv[0]);
712
        exit(EXIT_FAILURE);
B
bellard 已提交
713 714
    }

715 716
    if (qemu_opts_foreach(&qemu_object_opts,
                          user_creatable_add_opts_foreach,
717
                          NULL, NULL)) {
718 719 720
        exit(EXIT_FAILURE);
    }

721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
    if (tlscredsid) {
        if (sockpath) {
            error_report("TLS is only supported with IPv4/IPv6");
            exit(EXIT_FAILURE);
        }
        if (device) {
            error_report("TLS is not supported with a host device");
            exit(EXIT_FAILURE);
        }
        if (!export_name) {
            /* Set the default NBD protocol export name, since
             * we *must* use new style protocol for TLS */
            export_name = "";
        }
        tlscreds = nbd_get_tls_creds(tlscredsid, &local_err);
        if (local_err) {
            error_report("Failed to get TLS creds %s",
                         error_get_pretty(local_err));
            exit(EXIT_FAILURE);
        }
    }

743
    if (disconnect) {
744 745
        int nbdfd = open(argv[optind], O_RDWR);
        if (nbdfd < 0) {
746 747 748
            error_report("Cannot open %s: %s", argv[optind],
                         strerror(errno));
            exit(EXIT_FAILURE);
749
        }
750
        nbd_disconnect(nbdfd);
751

752
        close(nbdfd);
753 754 755

        printf("%s disconnected\n", argv[optind]);

756
        return 0;
757 758
    }

759 760 761 762 763
    if (device && !verbose) {
        int stderr_fd[2];
        pid_t pid;
        int ret;

764
        if (qemu_pipe(stderr_fd) < 0) {
765 766 767
            error_report("Error setting up communication pipe: %s",
                         strerror(errno));
            exit(EXIT_FAILURE);
768 769 770 771 772 773
        }

        /* Now daemonize, but keep a communication channel open to
         * print errors and exit with the proper status code.
         */
        pid = fork();
M
Max Reitz 已提交
774
        if (pid < 0) {
775 776
            error_report("Failed to fork: %s", strerror(errno));
            exit(EXIT_FAILURE);
M
Max Reitz 已提交
777
        } else if (pid == 0) {
778
            close(stderr_fd[0]);
779
            ret = qemu_daemon(1, 0);
780 781 782

            /* Temporarily redirect stderr to the parent's pipe...  */
            dup2(stderr_fd[1], STDERR_FILENO);
783
            if (ret < 0) {
784 785
                error_report("Failed to daemonize: %s", strerror(errno));
                exit(EXIT_FAILURE);
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
            }

            /* ... close the descriptor we inherited and go on.  */
            close(stderr_fd[1]);
        } else {
            bool errors = false;
            char *buf;

            /* In the parent.  Print error messages from the child until
             * it closes the pipe.
             */
            close(stderr_fd[1]);
            buf = g_malloc(1024);
            while ((ret = read(stderr_fd[0], buf, 1024)) > 0) {
                errors = true;
                ret = qemu_write_full(STDERR_FILENO, buf, ret);
802
                if (ret < 0) {
803 804 805
                    exit(EXIT_FAILURE);
                }
            }
806
            if (ret < 0) {
807 808 809
                error_report("Cannot read from daemon: %s",
                             strerror(errno));
                exit(EXIT_FAILURE);
810 811 812 813 814 815 816 817 818
            }

            /* Usually the daemon should not print any message.
             * Exit with zero status in that case.
             */
            exit(errors);
        }
    }

819 820 821
    if (device != NULL && sockpath == NULL) {
        sockpath = g_malloc(128);
        snprintf(sockpath, 128, SOCKET_PATH, basename(device));
822 823
    }

824 825
    saddr = nbd_build_socket_address(sockpath, bindto, port);

826
    if (qemu_init_main_loop(&local_err)) {
827
        error_report_err(local_err);
828 829
        exit(EXIT_FAILURE);
    }
830 831 832
    bdrv_init();
    atexit(bdrv_close_all);

833 834 835 836 837 838 839 840 841 842 843 844 845 846
    srcpath = argv[optind];
    if (imageOpts) {
        QemuOpts *opts;
        if (fmt) {
            error_report("--image-opts and -f are mutually exclusive");
            exit(EXIT_FAILURE);
        }
        opts = qemu_opts_parse_noisily(&file_opts, srcpath, true);
        if (!opts) {
            qemu_opts_reset(&file_opts);
            exit(EXIT_FAILURE);
        }
        options = qemu_opts_to_qdict(opts, NULL);
        qemu_opts_reset(&file_opts);
847
        blk = blk_new_open(NULL, NULL, options, flags, &local_err);
848 849 850 851 852
    } else {
        if (fmt) {
            options = qdict_new();
            qdict_put(options, "driver", qstring_from_str(fmt));
        }
853
        blk = blk_new_open(srcpath, NULL, options, flags, &local_err);
854 855
    }

856
    if (!blk) {
857 858
        error_reportf_err(local_err, "Failed to blk_new_open '%s': ",
                          argv[optind]);
859
        exit(EXIT_FAILURE);
860
    }
861
    bs = blk_bs(blk);
862

863 864
    blk_set_enable_write_cache(blk, !writethrough);

865 866 867 868 869 870 871 872 873 874
    if (sn_opts) {
        ret = bdrv_snapshot_load_tmp(bs,
                                     qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
                                     qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
                                     &local_err);
    } else if (sn_id_or_name) {
        ret = bdrv_snapshot_load_tmp_by_id_or_name(bs, sn_id_or_name,
                                                   &local_err);
    }
    if (ret < 0) {
875
        error_reportf_err(local_err, "Failed to load snapshot: ");
876
        exit(EXIT_FAILURE);
877 878
    }

879
    bs->detect_zeroes = detect_zeroes;
880
    fd_size = blk_getlength(blk);
M
Max Reitz 已提交
881
    if (fd_size < 0) {
882 883 884
        error_report("Failed to determine the image length: %s",
                     strerror(-fd_size));
        exit(EXIT_FAILURE);
M
Max Reitz 已提交
885
    }
886

887
    if (partition != -1) {
888
        ret = find_partition(blk, partition, &dev_offset, &fd_size);
889
        if (ret < 0) {
890
            error_report("Could not find partition %d: %s", partition,
891
                         strerror(-ret));
892
            exit(EXIT_FAILURE);
893
        }
894 895
    }

M
Max Reitz 已提交
896 897 898
    exp = nbd_export_new(blk, dev_offset, fd_size, nbdflags, nbd_export_closed,
                         &local_err);
    if (!exp) {
899
        error_report_err(local_err);
900
        exit(EXIT_FAILURE);
M
Max Reitz 已提交
901
    }
902 903 904 905
    if (export_name) {
        nbd_export_set_name(exp, export_name);
        newproto = true;
    }
906

907 908 909
    server_ioc = qio_channel_socket_new();
    if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) {
        object_unref(OBJECT(server_ioc));
910
        error_report_err(local_err);
B
bellard 已提交
911
        return 1;
P
Paolo Bonzini 已提交
912
    }
P
Paolo Bonzini 已提交
913 914 915 916

    if (device) {
        int ret;

917
        ret = pthread_create(&client_thread, NULL, nbd_client_thread, device);
P
Paolo Bonzini 已提交
918
        if (ret != 0) {
919 920
            error_report("Failed to create client thread: %s", strerror(ret));
            exit(EXIT_FAILURE);
P
Paolo Bonzini 已提交
921 922 923 924 925 926
        }
    } else {
        /* Shut up GCC warnings.  */
        memset(&client_thread, 0, sizeof(client_thread));
    }

927
    nbd_update_server_watch();
B
bellard 已提交
928

929 930 931
    /* now when the initialization is (almost) complete, chdir("/")
     * to free any busy filesystems */
    if (chdir("/") < 0) {
932 933 934
        error_report("Could not chdir to root directory: %s",
                     strerror(errno));
        exit(EXIT_FAILURE);
935 936
    }

937
    state = RUNNING;
938
    do {
P
Paolo Bonzini 已提交
939
        main_loop_wait(false);
940 941 942 943 944 945 946
        if (state == TERMINATE) {
            state = TERMINATING;
            nbd_export_close(exp);
            nbd_export_put(exp);
            exp = NULL;
        }
    } while (state != TERMINATED);
B
bellard 已提交
947

M
Markus Armbruster 已提交
948
    blk_unref(blk);
P
Paolo Bonzini 已提交
949 950 951
    if (sockpath) {
        unlink(sockpath);
    }
B
bellard 已提交
952

953
    qemu_opts_del(sn_opts);
954

P
Paolo Bonzini 已提交
955 956 957 958 959 960 961
    if (device) {
        void *ret;
        pthread_join(client_thread, &ret);
        exit(ret != NULL);
    } else {
        exit(EXIT_SUCCESS);
    }
B
bellard 已提交
962
}