File:  [Qemu by Fabrice Bellard] / qemu / qemu-nbd.c
Revision 1.1.1.7 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:17:15 2018 UTC (3 years, 3 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu1001, HEAD
qemu 1.0.1

    1: /*
    2:  *  Copyright (C) 2005  Anthony Liguori <anthony@codemonkey.ws>
    3:  *
    4:  *  Network Block Device
    5:  *
    6:  *  This program is free software; you can redistribute it and/or modify
    7:  *  it under the terms of the GNU General Public License as published by
    8:  *  the Free Software Foundation; under version 2 of the License.
    9:  *
   10:  *  This program is distributed in the hope that it will be useful,
   11:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   12:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13:  *  GNU General Public License for more details.
   14:  *
   15:  *  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/>.
   17:  */
   18: 
   19: #include "qemu-common.h"
   20: #include "block_int.h"
   21: #include "nbd.h"
   22: 
   23: #include <stdarg.h>
   24: #include <stdio.h>
   25: #include <getopt.h>
   26: #include <err.h>
   27: #include <sys/types.h>
   28: #include <sys/socket.h>
   29: #include <netinet/in.h>
   30: #include <netinet/tcp.h>
   31: #include <arpa/inet.h>
   32: #include <signal.h>
   33: #include <libgen.h>
   34: #include <pthread.h>
   35: 
   36: #define SOCKET_PATH    "/var/lock/qemu-nbd-%s"
   37: 
   38: #define NBD_BUFFER_SIZE (1024*1024)
   39: 
   40: static int sigterm_wfd;
   41: static int verbose;
   42: static char *device;
   43: static char *srcpath;
   44: static char *sockpath;
   45: 
   46: static void usage(const char *name)
   47: {
   48:     printf(
   49: "Usage: %s [OPTIONS] FILE\n"
   50: "QEMU Disk Network Block Device Server\n"
   51: "\n"
   52: "  -p, --port=PORT      port to listen on (default `%d')\n"
   53: "  -o, --offset=OFFSET  offset into the image\n"
   54: "  -b, --bind=IFACE     interface to bind to (default `0.0.0.0')\n"
   55: "  -k, --socket=PATH    path to the unix socket\n"
   56: "                       (default '"SOCKET_PATH"')\n"
   57: "  -r, --read-only      export read-only\n"
   58: "  -P, --partition=NUM  only expose partition NUM\n"
   59: "  -s, --snapshot       use snapshot file\n"
   60: "  -n, --nocache        disable host cache\n"
   61: "  -c, --connect=DEV    connect FILE to the local NBD device DEV\n"
   62: "  -d, --disconnect     disconnect the specified device\n"
   63: "  -e, --shared=NUM     device can be shared by NUM clients (default '1')\n"
   64: "  -t, --persistent     don't exit on the last connection\n"
   65: "  -v, --verbose        display extra debugging information\n"
   66: "  -h, --help           display this help and exit\n"
   67: "  -V, --version        output version information and exit\n"
   68: "\n"
   69: "Report bugs to <anthony@codemonkey.ws>\n"
   70:     , name, NBD_DEFAULT_PORT, "DEVICE");
   71: }
   72: 
   73: static void version(const char *name)
   74: {
   75:     printf(
   76: "%s version 0.0.1\n"
   77: "Written by Anthony Liguori.\n"
   78: "\n"
   79: "Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>.\n"
   80: "This is free software; see the source for copying conditions.  There is NO\n"
   81: "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
   82:     , name);
   83: }
   84: 
   85: struct partition_record
   86: {
   87:     uint8_t bootable;
   88:     uint8_t start_head;
   89:     uint32_t start_cylinder;
   90:     uint8_t start_sector;
   91:     uint8_t system;
   92:     uint8_t end_head;
   93:     uint8_t end_cylinder;
   94:     uint8_t end_sector;
   95:     uint32_t start_sector_abs;
   96:     uint32_t nb_sectors_abs;
   97: };
   98: 
   99: static void read_partition(uint8_t *p, struct partition_record *r)
  100: {
  101:     r->bootable = p[0];
  102:     r->start_head = p[1];
  103:     r->start_cylinder = p[3] | ((p[2] << 2) & 0x0300);
  104:     r->start_sector = p[2] & 0x3f;
  105:     r->system = p[4];
  106:     r->end_head = p[5];
  107:     r->end_cylinder = p[7] | ((p[6] << 2) & 0x300);
  108:     r->end_sector = p[6] & 0x3f;
  109:     r->start_sector_abs = p[8] | p[9] << 8 | p[10] << 16 | p[11] << 24;
  110:     r->nb_sectors_abs = p[12] | p[13] << 8 | p[14] << 16 | p[15] << 24;
  111: }
  112: 
  113: static int find_partition(BlockDriverState *bs, int partition,
  114:                           off_t *offset, off_t *size)
  115: {
  116:     struct partition_record mbr[4];
  117:     uint8_t data[512];
  118:     int i;
  119:     int ext_partnum = 4;
  120:     int ret;
  121: 
  122:     if ((ret = bdrv_read(bs, 0, data, 1)) < 0) {
  123:         errno = -ret;
  124:         err(EXIT_FAILURE, "error while reading");
  125:     }
  126: 
  127:     if (data[510] != 0x55 || data[511] != 0xaa) {
  128:         errno = -EINVAL;
  129:         return -1;
  130:     }
  131: 
  132:     for (i = 0; i < 4; i++) {
  133:         read_partition(&data[446 + 16 * i], &mbr[i]);
  134: 
  135:         if (!mbr[i].nb_sectors_abs)
  136:             continue;
  137: 
  138:         if (mbr[i].system == 0xF || mbr[i].system == 0x5) {
  139:             struct partition_record ext[4];
  140:             uint8_t data1[512];
  141:             int j;
  142: 
  143:             if ((ret = bdrv_read(bs, mbr[i].start_sector_abs, data1, 1)) < 0) {
  144:                 errno = -ret;
  145:                 err(EXIT_FAILURE, "error while reading");
  146:             }
  147: 
  148:             for (j = 0; j < 4; j++) {
  149:                 read_partition(&data1[446 + 16 * j], &ext[j]);
  150:                 if (!ext[j].nb_sectors_abs)
  151:                     continue;
  152: 
  153:                 if ((ext_partnum + j + 1) == partition) {
  154:                     *offset = (uint64_t)ext[j].start_sector_abs << 9;
  155:                     *size = (uint64_t)ext[j].nb_sectors_abs << 9;
  156:                     return 0;
  157:                 }
  158:             }
  159:             ext_partnum += 4;
  160:         } else if ((i + 1) == partition) {
  161:             *offset = (uint64_t)mbr[i].start_sector_abs << 9;
  162:             *size = (uint64_t)mbr[i].nb_sectors_abs << 9;
  163:             return 0;
  164:         }
  165:     }
  166: 
  167:     errno = -ENOENT;
  168:     return -1;
  169: }
  170: 
  171: static void termsig_handler(int signum)
  172: {
  173:     static int sigterm_reported;
  174:     if (!sigterm_reported) {
  175:         sigterm_reported = (write(sigterm_wfd, "", 1) == 1);
  176:     }
  177: }
  178: 
  179: static void *show_parts(void *arg)
  180: {
  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: }
  194: 
  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:             goto out;
  209:         }
  210:     } while (sock == -1);
  211: 
  212:     ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
  213:                                 &size, &blocksize);
  214:     if (ret == -1) {
  215:         goto out;
  216:     }
  217: 
  218:     ret = nbd_init(fd, sock, nbdflags, size, blocksize);
  219:     if (ret == -1) {
  220:         goto out;
  221:     }
  222: 
  223:     /* update partition table */
  224:     pthread_create(&show_parts_thread, NULL, show_parts, NULL);
  225: 
  226:     if (verbose) {
  227:         fprintf(stderr, "NBD device %s is now connected to %s\n",
  228:                 device, srcpath);
  229:     } else {
  230:         /* Close stderr so that the qemu-nbd process exits.  */
  231:         dup2(STDOUT_FILENO, STDERR_FILENO);
  232:     }
  233: 
  234:     ret = nbd_client(fd);
  235:     if (ret) {
  236:         goto out;
  237:     }
  238:     close(fd);
  239:     kill(getpid(), SIGTERM);
  240:     return (void *) EXIT_SUCCESS;
  241: 
  242: out:
  243:     kill(getpid(), SIGTERM);
  244:     return (void *) EXIT_FAILURE;
  245: }
  246: 
  247: int main(int argc, char **argv)
  248: {
  249:     BlockDriverState *bs;
  250:     off_t dev_offset = 0;
  251:     off_t offset = 0;
  252:     uint32_t nbdflags = 0;
  253:     bool disconnect = false;
  254:     const char *bindto = "0.0.0.0";
  255:     int port = NBD_DEFAULT_PORT;
  256:     struct sockaddr_in addr;
  257:     socklen_t addr_len = sizeof(addr);
  258:     off_t fd_size;
  259:     const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
  260:     struct option lopt[] = {
  261:         { "help", 0, NULL, 'h' },
  262:         { "version", 0, NULL, 'V' },
  263:         { "bind", 1, NULL, 'b' },
  264:         { "port", 1, NULL, 'p' },
  265:         { "socket", 1, NULL, 'k' },
  266:         { "offset", 1, NULL, 'o' },
  267:         { "read-only", 0, NULL, 'r' },
  268:         { "partition", 1, NULL, 'P' },
  269:         { "connect", 1, NULL, 'c' },
  270:         { "disconnect", 0, NULL, 'd' },
  271:         { "snapshot", 0, NULL, 's' },
  272:         { "nocache", 0, NULL, 'n' },
  273:         { "shared", 1, NULL, 'e' },
  274:         { "persistent", 0, NULL, 't' },
  275:         { "verbose", 0, NULL, 'v' },
  276:         { NULL, 0, NULL, 0 }
  277:     };
  278:     int ch;
  279:     int opt_ind = 0;
  280:     int li;
  281:     char *end;
  282:     int flags = BDRV_O_RDWR;
  283:     int partition = -1;
  284:     int ret;
  285:     int shared = 1;
  286:     uint8_t *data;
  287:     fd_set fds;
  288:     int *sharing_fds;
  289:     int fd;
  290:     int i;
  291:     int nb_fds = 0;
  292:     int max_fd;
  293:     int persistent = 0;
  294:     pthread_t client_thread;
  295: 
  296:     /* The client thread uses SIGTERM to interrupt the server.  A signal
  297:      * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
  298:      */
  299:     struct sigaction sa_sigterm;
  300:     int sigterm_fd[2];
  301:     if (qemu_pipe(sigterm_fd) == -1) {
  302:         err(EXIT_FAILURE, "Error setting up communication pipe");
  303:     }
  304: 
  305:     sigterm_wfd = sigterm_fd[1];
  306:     memset(&sa_sigterm, 0, sizeof(sa_sigterm));
  307:     sa_sigterm.sa_handler = termsig_handler;
  308:     sigaction(SIGTERM, &sa_sigterm, NULL);
  309: 
  310:     while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
  311:         switch (ch) {
  312:         case 's':
  313:             flags |= BDRV_O_SNAPSHOT;
  314:             break;
  315:         case 'n':
  316:             flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
  317:             break;
  318:         case 'b':
  319:             bindto = optarg;
  320:             break;
  321:         case 'p':
  322:             li = strtol(optarg, &end, 0);
  323:             if (*end) {
  324:                 errx(EXIT_FAILURE, "Invalid port `%s'", optarg);
  325:             }
  326:             if (li < 1 || li > 65535) {
  327:                 errx(EXIT_FAILURE, "Port out of range `%s'", optarg);
  328:             }
  329:             port = (uint16_t)li;
  330:             break;
  331:         case 'o':
  332:                 dev_offset = strtoll (optarg, &end, 0);
  333:             if (*end) {
  334:                 errx(EXIT_FAILURE, "Invalid offset `%s'", optarg);
  335:             }
  336:             if (dev_offset < 0) {
  337:                 errx(EXIT_FAILURE, "Offset must be positive `%s'", optarg);
  338:             }
  339:             break;
  340:         case 'r':
  341:             nbdflags |= NBD_FLAG_READ_ONLY;
  342:             flags &= ~BDRV_O_RDWR;
  343:             break;
  344:         case 'P':
  345:             partition = strtol(optarg, &end, 0);
  346:             if (*end)
  347:                 errx(EXIT_FAILURE, "Invalid partition `%s'", optarg);
  348:             if (partition < 1 || partition > 8)
  349:                 errx(EXIT_FAILURE, "Invalid partition %d", partition);
  350:             break;
  351:         case 'k':
  352:             sockpath = optarg;
  353:             if (sockpath[0] != '/')
  354:                 errx(EXIT_FAILURE, "socket path must be absolute\n");
  355:             break;
  356:         case 'd':
  357:             disconnect = true;
  358:             break;
  359:         case 'c':
  360:             device = optarg;
  361:             break;
  362:         case 'e':
  363:             shared = strtol(optarg, &end, 0);
  364:             if (*end) {
  365:                 errx(EXIT_FAILURE, "Invalid shared device number '%s'", optarg);
  366:             }
  367:             if (shared < 1) {
  368:                 errx(EXIT_FAILURE, "Shared device number must be greater than 0\n");
  369:             }
  370:             break;
  371: 	case 't':
  372: 	    persistent = 1;
  373: 	    break;
  374:         case 'v':
  375:             verbose = 1;
  376:             break;
  377:         case 'V':
  378:             version(argv[0]);
  379:             exit(0);
  380:             break;
  381:         case 'h':
  382:             usage(argv[0]);
  383:             exit(0);
  384:             break;
  385:         case '?':
  386:             errx(EXIT_FAILURE, "Try `%s --help' for more information.",
  387:                  argv[0]);
  388:         }
  389:     }
  390: 
  391:     if ((argc - optind) != 1) {
  392:         errx(EXIT_FAILURE, "Invalid number of argument.\n"
  393:              "Try `%s --help' for more information.",
  394:              argv[0]);
  395:     }
  396: 
  397:     if (disconnect) {
  398:         fd = open(argv[optind], O_RDWR);
  399:         if (fd == -1)
  400:             err(EXIT_FAILURE, "Cannot open %s", argv[optind]);
  401: 
  402:         nbd_disconnect(fd);
  403: 
  404:         close(fd);
  405: 
  406:         printf("%s disconnected\n", argv[optind]);
  407: 
  408: 	return 0;
  409:     }
  410: 
  411:     if (device && !verbose) {
  412:         int stderr_fd[2];
  413:         pid_t pid;
  414:         int ret;
  415: 
  416:         if (qemu_pipe(stderr_fd) == -1) {
  417:             err(EXIT_FAILURE, "Error setting up communication pipe");
  418:         }
  419: 
  420:         /* Now daemonize, but keep a communication channel open to
  421:          * print errors and exit with the proper status code.
  422:          */
  423:         pid = fork();
  424:         if (pid == 0) {
  425:             close(stderr_fd[0]);
  426:             ret = qemu_daemon(0, 0);
  427: 
  428:             /* Temporarily redirect stderr to the parent's pipe...  */
  429:             dup2(stderr_fd[1], STDERR_FILENO);
  430:             if (ret == -1) {
  431:                 err(EXIT_FAILURE, "Failed to daemonize");
  432:             }
  433: 
  434:             /* ... close the descriptor we inherited and go on.  */
  435:             close(stderr_fd[1]);
  436:         } else {
  437:             bool errors = false;
  438:             char *buf;
  439: 
  440:             /* In the parent.  Print error messages from the child until
  441:              * it closes the pipe.
  442:              */
  443:             close(stderr_fd[1]);
  444:             buf = g_malloc(1024);
  445:             while ((ret = read(stderr_fd[0], buf, 1024)) > 0) {
  446:                 errors = true;
  447:                 ret = qemu_write_full(STDERR_FILENO, buf, ret);
  448:                 if (ret == -1) {
  449:                     exit(EXIT_FAILURE);
  450:                 }
  451:             }
  452:             if (ret == -1) {
  453:                 err(EXIT_FAILURE, "Cannot read from daemon");
  454:             }
  455: 
  456:             /* Usually the daemon should not print any message.
  457:              * Exit with zero status in that case.
  458:              */
  459:             exit(errors);
  460:         }
  461:     }
  462: 
  463:     if (device) {
  464:         /* Open before spawning new threads.  In the future, we may
  465:          * drop privileges after opening.
  466:          */
  467:         fd = open(device, O_RDWR);
  468:         if (fd == -1) {
  469:             err(EXIT_FAILURE, "Failed to open %s", device);
  470:         }
  471: 
  472:         if (sockpath == NULL) {
  473:             sockpath = g_malloc(128);
  474:             snprintf(sockpath, 128, SOCKET_PATH, basename(device));
  475:         }
  476:     }
  477: 
  478:     bdrv_init();
  479:     atexit(bdrv_close_all);
  480: 
  481:     bs = bdrv_new("hda");
  482:     srcpath = argv[optind];
  483:     if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) {
  484:         errno = -ret;
  485:         err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
  486:     }
  487: 
  488:     fd_size = bs->total_sectors * 512;
  489: 
  490:     if (partition != -1 &&
  491:         find_partition(bs, partition, &dev_offset, &fd_size)) {
  492:         err(EXIT_FAILURE, "Could not find partition %d", partition);
  493:     }
  494: 
  495:     sharing_fds = g_malloc((shared + 1) * sizeof(int));
  496: 
  497:     if (sockpath) {
  498:         sharing_fds[0] = unix_socket_incoming(sockpath);
  499:     } else {
  500:         sharing_fds[0] = tcp_socket_incoming(bindto, port);
  501:     }
  502: 
  503:     if (sharing_fds[0] == -1)
  504:         return 1;
  505: 
  506:     if (device) {
  507:         int ret;
  508: 
  509:         ret = pthread_create(&client_thread, NULL, nbd_client_thread, &fd);
  510:         if (ret != 0) {
  511:             errx(EXIT_FAILURE, "Failed to create client thread: %s",
  512:                  strerror(ret));
  513:         }
  514:     } else {
  515:         /* Shut up GCC warnings.  */
  516:         memset(&client_thread, 0, sizeof(client_thread));
  517:     }
  518: 
  519:     max_fd = sharing_fds[0];
  520:     nb_fds++;
  521: 
  522:     data = qemu_blockalign(bs, NBD_BUFFER_SIZE);
  523:     if (data == NULL) {
  524:         errx(EXIT_FAILURE, "Cannot allocate data buffer");
  525:     }
  526: 
  527:     do {
  528:         FD_ZERO(&fds);
  529:         FD_SET(sigterm_fd[0], &fds);
  530:         for (i = 0; i < nb_fds; i++)
  531:             FD_SET(sharing_fds[i], &fds);
  532: 
  533:         do {
  534:             ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
  535:         } while (ret == -1 && errno == EINTR);
  536:         if (ret == -1 || FD_ISSET(sigterm_fd[0], &fds)) {
  537:             break;
  538:         }
  539: 
  540:         if (FD_ISSET(sharing_fds[0], &fds))
  541:             ret--;
  542:         for (i = 1; i < nb_fds && ret; i++) {
  543:             if (FD_ISSET(sharing_fds[i], &fds)) {
  544:                 if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
  545:                     &offset, nbdflags, data, NBD_BUFFER_SIZE) != 0) {
  546:                     close(sharing_fds[i]);
  547:                     nb_fds--;
  548:                     sharing_fds[i] = sharing_fds[nb_fds];
  549:                     i--;
  550:                 }
  551:                 ret--;
  552:             }
  553:         }
  554:         /* new connection ? */
  555:         if (FD_ISSET(sharing_fds[0], &fds)) {
  556:             if (nb_fds < shared + 1) {
  557:                 sharing_fds[nb_fds] = accept(sharing_fds[0],
  558:                                              (struct sockaddr *)&addr,
  559:                                              &addr_len);
  560:                 if (sharing_fds[nb_fds] != -1 &&
  561:                     nbd_negotiate(sharing_fds[nb_fds], fd_size, nbdflags) != -1) {
  562:                         if (sharing_fds[nb_fds] > max_fd)
  563:                             max_fd = sharing_fds[nb_fds];
  564:                         nb_fds++;
  565:                 }
  566:             }
  567:         }
  568:     } while (persistent || nb_fds > 1);
  569:     qemu_vfree(data);
  570: 
  571:     close(sharing_fds[0]);
  572:     g_free(sharing_fds);
  573:     if (sockpath) {
  574:         unlink(sockpath);
  575:     }
  576: 
  577:     if (device) {
  578:         void *ret;
  579:         pthread_join(client_thread, &ret);
  580:         exit(ret != NULL);
  581:     } else {
  582:         exit(EXIT_SUCCESS);
  583:     }
  584: }

unix.superglobalmegacorp.com