qemu-nbd.c 28.1 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 "qemu-common.h"
M
Markus Armbruster 已提交
21
#include "sysemu/block-backend.h"
22
#include "block/block_int.h"
23
#include "block/nbd.h"
24
#include "qemu/main-loop.h"
25
#include "qemu/error-report.h"
26
#include "qemu/config-file.h"
27
#include "block/snapshot.h"
28
#include "qapi/util.h"
29
#include "qapi/qmp/qstring.h"
30
#include "qom/object_interfaces.h"
31
#include "io/channel-socket.h"
B
bellard 已提交
32 33

#include <getopt.h>
34 35
#include <sys/types.h>
#include <signal.h>
36
#include <libgen.h>
P
Paolo Bonzini 已提交
37
#include <pthread.h>
38

39
#define SOCKET_PATH                "/var/lock/qemu-nbd-%s"
40 41 42 43 44 45 46
#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 已提交
47

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

static void usage(const char *name)
{
63
    (printf) (
B
bellard 已提交
64 65 66
"Usage: %s [OPTIONS] FILE\n"
"QEMU Disk Network Block Device Server\n"
"\n"
67 68
"  -h, --help                display this help and exit\n"
"  -V, --version             output version information and exit\n"
69 70
"\n"
"Connection properties:\n"
71 72 73 74 75 76 77
"  -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"
B
bellard 已提交
78
"\n"
79
"Exposing part of the image:\n"
80 81
"  -o, --offset=OFFSET       offset into the image\n"
"  -P, --partition=NUM       only expose partition NUM\n"
82
"\n"
83 84 85
"General purpose options:\n"
"  --object type,id=ID,...   define an object such as 'secret' for providing\n"
"                            passwords and/or encryption keys\n"
86 87
#ifdef __linux__
"Kernel NBD client support:\n"
88 89
"  -c, --connect=DEV         connect FILE to the local NBD device DEV\n"
"  -d, --disconnect          disconnect the specified device\n"
90 91 92 93
"\n"
#endif
"\n"
"Block device options:\n"
94 95 96 97 98
"  -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"
99
"  -l, --load-snapshot=SNAPSHOT_PARAM\n"
100 101 102 103 104 105 106
"                            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"
107
"      --discard=MODE        set discard mode (ignore, unmap)\n"
108
"      --detect-zeroes=MODE  set detect-zeroes mode (off, on, unmap)\n"
109
"      --image-opts          treat FILE as a full set of image options\n"
110 111
"\n"
"Report bugs to <qemu-devel@nongnu.org>\n"
112
    , name, NBD_DEFAULT_PORT, "DEVICE");
B
bellard 已提交
113 114 115 116 117
}

static void version(const char *name)
{
    printf(
118
"%s version 0.0.1\n"
B
bellard 已提交
119 120 121 122 123
"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"
124
    , name);
B
bellard 已提交
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
}

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;
151 152 153

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

156
static int find_partition(BlockBackend *blk, int partition,
B
bellard 已提交
157 158 159 160 161 162
                          off_t *offset, off_t *size)
{
    struct partition_record mbr[4];
    uint8_t data[512];
    int i;
    int ext_partnum = 4;
R
Ryota Ozaki 已提交
163
    int ret;
B
bellard 已提交
164

165
    if ((ret = blk_read(blk, 0, data, 1)) < 0) {
166
        error_report("error while reading: %s", strerror(-ret));
167
        exit(EXIT_FAILURE);
R
Ryota Ozaki 已提交
168
    }
B
bellard 已提交
169 170

    if (data[510] != 0x55 || data[511] != 0xaa) {
171
        return -EINVAL;
B
bellard 已提交
172 173 174 175 176
    }

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

177
        if (!mbr[i].system || !mbr[i].nb_sectors_abs) {
B
bellard 已提交
178
            continue;
179
        }
B
bellard 已提交
180 181 182 183 184 185

        if (mbr[i].system == 0xF || mbr[i].system == 0x5) {
            struct partition_record ext[4];
            uint8_t data1[512];
            int j;

186
            if ((ret = blk_read(blk, mbr[i].start_sector_abs, data1, 1)) < 0) {
187
                error_report("error while reading: %s", strerror(-ret));
188
                exit(EXIT_FAILURE);
R
Ryota Ozaki 已提交
189
            }
B
bellard 已提交
190 191 192

            for (j = 0; j < 4; j++) {
                read_partition(&data1[446 + 16 * j], &ext[j]);
193
                if (!ext[j].system || !ext[j].nb_sectors_abs) {
B
bellard 已提交
194
                    continue;
195
                }
B
bellard 已提交
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210

                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;
        }
    }

211
    return -ENOENT;
B
bellard 已提交
212 213
}

P
Paolo Bonzini 已提交
214 215
static void termsig_handler(int signum)
{
216
    state = TERMINATE;
P
Paolo Bonzini 已提交
217
    qemu_notify_event();
P
Paolo Bonzini 已提交
218 219
}

220

P
Paolo Bonzini 已提交
221
static void *show_parts(void *arg)
222
{
223
    char *device = arg;
P
Paolo Bonzini 已提交
224 225 226 227 228 229 230 231
    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);
232
    if (nbd >= 0) {
P
Paolo Bonzini 已提交
233 234 235 236
        close(nbd);
    }
    return NULL;
}
237

P
Paolo Bonzini 已提交
238 239
static void *nbd_client_thread(void *arg)
{
240
    char *device = arg;
P
Paolo Bonzini 已提交
241 242
    off_t size;
    uint32_t nbdflags;
243 244
    QIOChannelSocket *sioc;
    int fd;
P
Paolo Bonzini 已提交
245 246
    int ret;
    pthread_t show_parts_thread;
M
Max Reitz 已提交
247
    Error *local_error = NULL;
P
Paolo Bonzini 已提交
248

249 250 251 252
    sioc = qio_channel_socket_new();
    if (qio_channel_socket_connect_sync(sioc,
                                        saddr,
                                        &local_error) < 0) {
253
        error_report_err(local_error);
254 255
        goto out;
    }
P
Paolo Bonzini 已提交
256

257
    ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), NULL, &nbdflags,
258
                                NULL, NULL, NULL,
259
                                &size, &local_error);
260
    if (ret < 0) {
M
Max Reitz 已提交
261
        if (local_error) {
262
            error_report_err(local_error);
M
Max Reitz 已提交
263
        }
P
Paolo Bonzini 已提交
264
        goto out_socket;
P
Paolo Bonzini 已提交
265 266
    }

267
    fd = open(device, O_RDWR);
268
    if (fd < 0) {
269
        /* Linux-only, we can use %m in printf.  */
270
        error_report("Failed to open %s: %m", device);
P
Paolo Bonzini 已提交
271
        goto out_socket;
272 273
    }

274
    ret = nbd_init(fd, sioc, nbdflags, size);
275
    if (ret < 0) {
P
Paolo Bonzini 已提交
276
        goto out_fd;
P
Paolo Bonzini 已提交
277 278 279
    }

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

282 283 284 285 286 287 288
    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 已提交
289 290 291

    ret = nbd_client(fd);
    if (ret) {
P
Paolo Bonzini 已提交
292
        goto out_fd;
293
    }
P
Paolo Bonzini 已提交
294
    close(fd);
295
    object_unref(OBJECT(sioc));
P
Paolo Bonzini 已提交
296 297 298
    kill(getpid(), SIGTERM);
    return (void *) EXIT_SUCCESS;

P
Paolo Bonzini 已提交
299 300 301
out_fd:
    close(fd);
out_socket:
302
    object_unref(OBJECT(sioc));
P
Paolo Bonzini 已提交
303 304 305
out:
    kill(getpid(), SIGTERM);
    return (void *) EXIT_FAILURE;
306 307
}

308
static int nbd_can_accept(void)
P
Paolo Bonzini 已提交
309 310 311 312
{
    return nb_fds < shared;
}

313 314 315 316 317 318
static void nbd_export_closed(NBDExport *exp)
{
    assert(state == TERMINATING);
    state = TERMINATED;
}

319
static void nbd_update_server_watch(void);
320

321
static void nbd_client_closed(NBDClient *client)
P
Paolo Bonzini 已提交
322
{
323
    nb_fds--;
324 325 326
    if (nb_fds == 0 && !persistent && state == RUNNING) {
        state = TERMINATE;
    }
327
    nbd_update_server_watch();
328
    nbd_client_put(client);
P
Paolo Bonzini 已提交
329 330
}

331
static gboolean nbd_accept(QIOChannel *ioc, GIOCondition cond, gpointer opaque)
P
Paolo Bonzini 已提交
332
{
333
    QIOChannelSocket *cioc;
P
Paolo Bonzini 已提交
334

335 336 337 338
    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
                                     NULL);
    if (!cioc) {
        return TRUE;
P
Paolo Bonzini 已提交
339 340
    }

341
    if (state >= TERMINATE) {
342 343
        object_unref(OBJECT(cioc));
        return TRUE;
344 345
    }

346
    nb_fds++;
347
    nbd_update_server_watch();
348
    nbd_client_new(newproto ? NULL : exp, cioc,
349
                   tlscreds, NULL, nbd_client_closed);
350 351 352
    object_unref(OBJECT(cioc));

    return TRUE;
P
Paolo Bonzini 已提交
353 354
}

355
static void nbd_update_server_watch(void)
356 357
{
    if (nbd_can_accept()) {
358 359 360 361 362 363
        if (server_watch == -1) {
            server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc),
                                                 G_IO_IN,
                                                 nbd_accept,
                                                 NULL, NULL);
        }
364
    } else {
365 366 367 368
        if (server_watch != -1) {
            g_source_remove(server_watch);
            server_watch = -1;
        }
369 370 371
    }
}

372 373 374 375 376 377 378 379 380

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

    saddr = g_new0(SocketAddress, 1);
    if (sockpath) {
381 382 383
        saddr->type = SOCKET_ADDRESS_KIND_UNIX;
        saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
        saddr->u.q_unix->path = g_strdup(sockpath);
384
    } else {
385 386 387
        saddr->type = SOCKET_ADDRESS_KIND_INET;
        saddr->u.inet = g_new0(InetSocketAddress, 1);
        saddr->u.inet->host = g_strdup(bindto);
388
        if (port) {
389
            saddr->u.inet->port = g_strdup(port);
390
        } else  {
391
            saddr->u.inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT);
392 393 394 395 396 397 398
        }
    }

    return saddr;
}


399 400 401 402 403 404 405 406 407 408
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 */ }
    },
};

409 410 411 412 413 414 415 416 417 418
static QemuOptsList qemu_object_opts = {
    .name = "object",
    .implied_opt_name = "qom-type",
    .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
    .desc = {
        { }
    },
};


419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449

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

P
Paolo Bonzini 已提交
511 512 513
    /* 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 已提交
514 515 516 517
    struct sigaction sa_sigterm;
    memset(&sa_sigterm, 0, sizeof(sa_sigterm));
    sa_sigterm.sa_handler = termsig_handler;
    sigaction(SIGTERM, &sa_sigterm, NULL);
518 519
    module_call_init(MODULE_INIT_QOM);
    qemu_add_opts(&qemu_object_opts);
520
    qemu_init_exec_dir(argv[0]);
P
Paolo Bonzini 已提交
521

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

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

701 702 703 704 705 706 707
    if (qemu_opts_foreach(&qemu_object_opts,
                          user_creatable_add_opts_foreach,
                          NULL, &local_err)) {
        error_report_err(local_err);
        exit(EXIT_FAILURE);
    }

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
    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);
        }
    }

730
    if (disconnect) {
731 732
        int nbdfd = open(argv[optind], O_RDWR);
        if (nbdfd < 0) {
733 734 735
            error_report("Cannot open %s: %s", argv[optind],
                         strerror(errno));
            exit(EXIT_FAILURE);
736
        }
737
        nbd_disconnect(nbdfd);
738

739
        close(nbdfd);
740 741 742

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

743
        return 0;
744 745
    }

746 747 748 749 750
    if (device && !verbose) {
        int stderr_fd[2];
        pid_t pid;
        int ret;

751
        if (qemu_pipe(stderr_fd) < 0) {
752 753 754
            error_report("Error setting up communication pipe: %s",
                         strerror(errno));
            exit(EXIT_FAILURE);
755 756 757 758 759 760
        }

        /* Now daemonize, but keep a communication channel open to
         * print errors and exit with the proper status code.
         */
        pid = fork();
M
Max Reitz 已提交
761
        if (pid < 0) {
762 763
            error_report("Failed to fork: %s", strerror(errno));
            exit(EXIT_FAILURE);
M
Max Reitz 已提交
764
        } else if (pid == 0) {
765
            close(stderr_fd[0]);
766
            ret = qemu_daemon(1, 0);
767 768 769

            /* Temporarily redirect stderr to the parent's pipe...  */
            dup2(stderr_fd[1], STDERR_FILENO);
770
            if (ret < 0) {
771 772
                error_report("Failed to daemonize: %s", strerror(errno));
                exit(EXIT_FAILURE);
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
            }

            /* ... 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);
789
                if (ret < 0) {
790 791 792
                    exit(EXIT_FAILURE);
                }
            }
793
            if (ret < 0) {
794 795 796
                error_report("Cannot read from daemon: %s",
                             strerror(errno));
                exit(EXIT_FAILURE);
797 798 799 800 801 802 803 804 805
            }

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

806 807 808
    if (device != NULL && sockpath == NULL) {
        sockpath = g_malloc(128);
        snprintf(sockpath, 128, SOCKET_PATH, basename(device));
809 810
    }

811 812
    saddr = nbd_build_socket_address(sockpath, bindto, port);

813
    if (qemu_init_main_loop(&local_err)) {
814
        error_report_err(local_err);
815 816
        exit(EXIT_FAILURE);
    }
817 818 819
    bdrv_init();
    atexit(bdrv_close_all);

820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
    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);
        blk = blk_new_open("hda", NULL, NULL, options, flags, &local_err);
    } else {
        if (fmt) {
            options = qdict_new();
            qdict_put(options, "driver", qstring_from_str(fmt));
        }
        blk = blk_new_open("hda", srcpath, NULL, options, flags, &local_err);
841 842
    }

843
    if (!blk) {
844 845
        error_reportf_err(local_err, "Failed to blk_new_open '%s': ",
                          argv[optind]);
846
        exit(EXIT_FAILURE);
847
    }
848
    bs = blk_bs(blk);
849

850 851 852 853 854 855 856 857 858 859
    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) {
860
        error_reportf_err(local_err, "Failed to load snapshot: ");
861
        exit(EXIT_FAILURE);
862 863
    }

864
    bs->detect_zeroes = detect_zeroes;
865
    fd_size = blk_getlength(blk);
M
Max Reitz 已提交
866
    if (fd_size < 0) {
867 868 869
        error_report("Failed to determine the image length: %s",
                     strerror(-fd_size));
        exit(EXIT_FAILURE);
M
Max Reitz 已提交
870
    }
871

872
    if (partition != -1) {
873
        ret = find_partition(blk, partition, &dev_offset, &fd_size);
874
        if (ret < 0) {
875
            error_report("Could not find partition %d: %s", partition,
876
                         strerror(-ret));
877
            exit(EXIT_FAILURE);
878
        }
879 880
    }

M
Max Reitz 已提交
881 882 883
    exp = nbd_export_new(blk, dev_offset, fd_size, nbdflags, nbd_export_closed,
                         &local_err);
    if (!exp) {
884
        error_report_err(local_err);
885
        exit(EXIT_FAILURE);
M
Max Reitz 已提交
886
    }
887 888 889 890
    if (export_name) {
        nbd_export_set_name(exp, export_name);
        newproto = true;
    }
891

892 893 894
    server_ioc = qio_channel_socket_new();
    if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) {
        object_unref(OBJECT(server_ioc));
895
        error_report_err(local_err);
B
bellard 已提交
896
        return 1;
P
Paolo Bonzini 已提交
897
    }
P
Paolo Bonzini 已提交
898 899 900 901

    if (device) {
        int ret;

902
        ret = pthread_create(&client_thread, NULL, nbd_client_thread, device);
P
Paolo Bonzini 已提交
903
        if (ret != 0) {
904 905
            error_report("Failed to create client thread: %s", strerror(ret));
            exit(EXIT_FAILURE);
P
Paolo Bonzini 已提交
906 907 908 909 910 911
        }
    } else {
        /* Shut up GCC warnings.  */
        memset(&client_thread, 0, sizeof(client_thread));
    }

912
    nbd_update_server_watch();
B
bellard 已提交
913

914 915 916
    /* now when the initialization is (almost) complete, chdir("/")
     * to free any busy filesystems */
    if (chdir("/") < 0) {
917 918 919
        error_report("Could not chdir to root directory: %s",
                     strerror(errno));
        exit(EXIT_FAILURE);
920 921
    }

922
    state = RUNNING;
923
    do {
P
Paolo Bonzini 已提交
924
        main_loop_wait(false);
925 926 927 928 929 930 931
        if (state == TERMINATE) {
            state = TERMINATING;
            nbd_export_close(exp);
            nbd_export_put(exp);
            exp = NULL;
        }
    } while (state != TERMINATED);
B
bellard 已提交
932

M
Markus Armbruster 已提交
933
    blk_unref(blk);
P
Paolo Bonzini 已提交
934 935 936
    if (sockpath) {
        unlink(sockpath);
    }
B
bellard 已提交
937

938
    qemu_opts_del(sn_opts);
939

P
Paolo Bonzini 已提交
940 941 942 943 944 945 946
    if (device) {
        void *ret;
        pthread_join(client_thread, &ret);
        exit(ret != NULL);
    } else {
        exit(EXIT_SUCCESS);
    }
B
bellard 已提交
947
}