Revision a517e88b qemu-nbd.c

b/qemu-nbd.c
31 31
#include <arpa/inet.h>
32 32
#include <signal.h>
33 33
#include <libgen.h>
34
#include <pthread.h>
34 35

  
35 36
#define SOCKET_PATH    "/var/lock/qemu-nbd-%s"
36 37

  
......
38 39

  
39 40
static int sigterm_wfd;
40 41
static int verbose;
42
static char *device;
43
static char *srcpath;
44
static char *sockpath;
41 45

  
42 46
static void usage(const char *name)
43 47
{
......
172 176
    }
173 177
}
174 178

  
175
static void show_parts(const char *device)
179
static void *show_parts(void *arg)
176 180
{
177
    if (fork() == 0) {
178
        int nbd;
181
    int nbd;
182

  
183
    /* linux just needs an open() to trigger
184
     * the partition table update
185
     * but remember to load the module with max_part != 0 :
186
     *     modprobe nbd max_part=63
187
     */
188
    nbd = open(device, O_RDWR);
189
    if (nbd != -1) {
190
        close(nbd);
191
    }
192
    return NULL;
193
}
179 194

  
180
        /* linux just needs an open() to trigger
181
         * the partition table update
182
         * but remember to load the module with max_part != 0 :
183
         *     modprobe nbd max_part=63
184
         */
185
        nbd = open(device, O_RDWR);
186
        if (nbd != -1)
187
              close(nbd);
188
        exit(0);
195
static void *nbd_client_thread(void *arg)
196
{
197
    int fd = *(int *)arg;
198
    off_t size;
199
    size_t blocksize;
200
    uint32_t nbdflags;
201
    int sock;
202
    int ret;
203
    pthread_t show_parts_thread;
204

  
205
    do {
206
        sock = unix_socket_outgoing(sockpath);
207
        if (sock == -1) {
208
            if (errno != ENOENT && errno != ECONNREFUSED) {
209
                goto out;
210
            }
211
            sleep(1);  /* wait parent */
212
        }
213
    } while (sock == -1);
214

  
215
    ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
216
                                &size, &blocksize);
217
    if (ret == -1) {
218
        goto out;
219
    }
220

  
221
    ret = nbd_init(fd, sock, nbdflags, size, blocksize);
222
    if (ret == -1) {
223
        goto out;
224
    }
225

  
226
    /* update partition table */
227
    pthread_create(&show_parts_thread, NULL, show_parts, NULL);
228

  
229
    fprintf(stderr, "NBD device %s is now connected to %s\n",
230
            device, srcpath);
231

  
232
    ret = nbd_client(fd);
233
    if (ret) {
234
        goto out;
189 235
    }
236
    close(fd);
237
    kill(getpid(), SIGTERM);
238
    return (void *) EXIT_SUCCESS;
239

  
240
out:
241
    kill(getpid(), SIGTERM);
242
    return (void *) EXIT_FAILURE;
190 243
}
191 244

  
192 245
int main(int argc, char **argv)
......
201 254
    struct sockaddr_in addr;
202 255
    socklen_t addr_len = sizeof(addr);
203 256
    off_t fd_size;
204
    char *device = NULL;
205
    char *sockpath = NULL;
206 257
    const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
207 258
    struct option lopt[] = {
208 259
        { "help", 0, NULL, 'h' },
......
238 289
    int nb_fds = 0;
239 290
    int max_fd;
240 291
    int persistent = 0;
292
    pthread_t client_thread;
241 293

  
242
    /* Set up a SIGTERM handler so that we exit with a nice status code.  */
294
    /* The client thread uses SIGTERM to interrupt the server.  A signal
295
     * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
296
     */
243 297
    struct sigaction sa_sigterm;
244 298
    int sigterm_fd[2];
245 299
    if (qemu_pipe(sigterm_fd) == -1) {
......
356 410

  
357 411
    bs = bdrv_new("hda");
358 412

  
359
    if ((ret = bdrv_open(bs, argv[optind], flags, NULL)) < 0) {
413
    srcpath = argv[optind];
414
    if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) {
360 415
        errno = -ret;
361
        err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
416
        err(EXIT_FAILURE, "Failed to bdrv_open '%s'", srcpath);
362 417
    }
363 418

  
364 419
    fd_size = bs->total_sectors * 512;
......
368 423
        err(EXIT_FAILURE, "Could not find partition %d", partition);
369 424

  
370 425
    if (device) {
371
        pid_t pid;
372
        int sock;
426
        int ret;
373 427

  
374
        /* want to fail before daemonizing */
375
        if (access(device, R_OK|W_OK) == -1) {
376
            err(EXIT_FAILURE, "Could not access '%s'", device);
428
        /* Open before spawning new threads.  In the future, we may
429
         * drop privileges after opening.
430
         */
431
        fd = open(device, O_RDWR);
432
        if (fd == -1) {
433
            err(EXIT_FAILURE, "Failed to open %s", device);
377 434
        }
378 435

  
379 436
        if (!verbose) {
......
388 445
            snprintf(sockpath, 128, SOCKET_PATH, basename(device));
389 446
        }
390 447

  
391
        pid = fork();
392
        if (pid < 0)
393
            return 1;
394
        if (pid != 0) {
395
            off_t size;
396
            size_t blocksize;
397

  
398
            ret = 0;
399
            bdrv_close(bs);
400

  
401
            do {
402
                sock = unix_socket_outgoing(sockpath);
403
                if (sock == -1) {
404
                    if (errno != ENOENT && errno != ECONNREFUSED) {
405
                        ret = 1;
406
                        goto out;
407
                    }
408
                    sleep(1);	/* wait children */
409
                }
410
            } while (sock == -1);
411

  
412
            fd = open(device, O_RDWR);
413
            if (fd == -1) {
414
                ret = 1;
415
                goto out;
416
            }
417

  
418
            ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
419
                                        &size, &blocksize);
420
            if (ret == -1) {
421
                ret = 1;
422
                goto out;
423
            }
424

  
425
            ret = nbd_init(fd, sock, nbdflags, size, blocksize);
426
            if (ret == -1) {
427
                ret = 1;
428
                goto out;
429
            }
430

  
431
            printf("NBD device %s is now connected to file %s\n",
432
                    device, argv[optind]);
433

  
434
	    /* update partition table */
435

  
436
            show_parts(device);
437

  
438
            ret = nbd_client(fd);
439
            if (ret) {
440
                ret = 1;
441
            }
442
            close(fd);
443
 out:
444
            kill(pid, SIGTERM);
445

  
446
            return ret;
448
        ret = pthread_create(&client_thread, NULL, nbd_client_thread, &fd);
449
        if (ret != 0) {
450
            errx(EXIT_FAILURE, "Failed to create client thread: %s",
451
                 strerror(ret));
447 452
        }
448
        /* children */
453
    } else {
454
        /* Shut up GCC warnings.  */
455
        memset(&client_thread, 0, sizeof(client_thread));
449 456
    }
450 457

  
451 458
    sharing_fds = g_malloc((shared + 1) * sizeof(int));
......
517 524
        unlink(sockpath);
518 525
    }
519 526

  
520
    return 0;
527
    if (device) {
528
        void *ret;
529
        pthread_join(client_thread, &ret);
530
        exit(ret != NULL);
531
    } else {
532
        exit(EXIT_SUCCESS);
533
    }
521 534
}

Also available in: Unified diff