Annotation of qemu/nbd.c, revision 1.1

1.1     ! root        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, write to the Free Software
        !            17:  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
        !            18:  */
        !            19: 
        !            20: #include "nbd.h"
        !            21: 
        !            22: #include <errno.h>
        !            23: #include <string.h>
        !            24: #ifndef _WIN32
        !            25: #include <sys/ioctl.h>
        !            26: #endif
        !            27: #ifdef __sun__
        !            28: #include <sys/ioccom.h>
        !            29: #endif
        !            30: #include <ctype.h>
        !            31: #include <inttypes.h>
        !            32: 
        !            33: #include "qemu_socket.h"
        !            34: 
        !            35: //#define DEBUG_NBD
        !            36: 
        !            37: #ifdef DEBUG_NBD
        !            38: #define TRACE(msg, ...) do { \
        !            39:     LOG(msg, ## __VA_ARGS__); \
        !            40: } while(0)
        !            41: #else
        !            42: #define TRACE(msg, ...) \
        !            43:     do { } while (0)
        !            44: #endif
        !            45: 
        !            46: #define LOG(msg, ...) do { \
        !            47:     fprintf(stderr, "%s:%s():L%d: " msg "\n", \
        !            48:             __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
        !            49: } while(0)
        !            50: 
        !            51: /* This is all part of the "official" NBD API */
        !            52: 
        !            53: #define NBD_REQUEST_MAGIC       0x25609513
        !            54: #define NBD_REPLY_MAGIC         0x67446698
        !            55: 
        !            56: #define NBD_SET_SOCK            _IO(0xab, 0)
        !            57: #define NBD_SET_BLKSIZE         _IO(0xab, 1)
        !            58: #define NBD_SET_SIZE            _IO(0xab, 2)
        !            59: #define NBD_DO_IT               _IO(0xab, 3)
        !            60: #define NBD_CLEAR_SOCK          _IO(0xab, 4)
        !            61: #define NBD_CLEAR_QUE           _IO(0xab, 5)
        !            62: #define NBD_PRINT_DEBUG                _IO(0xab, 6)
        !            63: #define NBD_SET_SIZE_BLOCKS    _IO(0xab, 7)
        !            64: #define NBD_DISCONNECT          _IO(0xab, 8)
        !            65: 
        !            66: /* That's all folks */
        !            67: 
        !            68: #define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
        !            69: #define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
        !            70: 
        !            71: size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
        !            72: {
        !            73:     size_t offset = 0;
        !            74: 
        !            75:     while (offset < size) {
        !            76:         ssize_t len;
        !            77: 
        !            78:         if (do_read) {
        !            79:             len = recv(fd, buffer + offset, size - offset, 0);
        !            80:         } else {
        !            81:             len = send(fd, buffer + offset, size - offset, 0);
        !            82:         }
        !            83: 
        !            84:         if (len == -1)
        !            85:             errno = socket_error();
        !            86: 
        !            87:         /* recoverable error */
        !            88:         if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
        !            89:             continue;
        !            90:         }
        !            91: 
        !            92:         /* eof */
        !            93:         if (len == 0) {
        !            94:             break;
        !            95:         }
        !            96: 
        !            97:         /* unrecoverable error */
        !            98:         if (len == -1) {
        !            99:             return 0;
        !           100:         }
        !           101: 
        !           102:         offset += len;
        !           103:     }
        !           104: 
        !           105:     return offset;
        !           106: }
        !           107: 
        !           108: int tcp_socket_outgoing(const char *address, uint16_t port)
        !           109: {
        !           110:     int s;
        !           111:     struct in_addr in;
        !           112:     struct sockaddr_in addr;
        !           113: 
        !           114:     s = socket(PF_INET, SOCK_STREAM, 0);
        !           115:     if (s == -1) {
        !           116:         return -1;
        !           117:     }
        !           118: 
        !           119:     if (inet_aton(address, &in) == 0) {
        !           120:         struct hostent *ent;
        !           121: 
        !           122:         ent = gethostbyname(address);
        !           123:         if (ent == NULL) {
        !           124:             goto error;
        !           125:         }
        !           126: 
        !           127:         memcpy(&in, ent->h_addr, sizeof(in));
        !           128:     }
        !           129: 
        !           130:     addr.sin_family = AF_INET;
        !           131:     addr.sin_port = htons(port);
        !           132:     memcpy(&addr.sin_addr.s_addr, &in, sizeof(in));
        !           133: 
        !           134:     if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        !           135:         goto error;
        !           136:     }
        !           137: 
        !           138:     return s;
        !           139: error:
        !           140:     closesocket(s);
        !           141:     return -1;
        !           142: }
        !           143: 
        !           144: int tcp_socket_incoming(const char *address, uint16_t port)
        !           145: {
        !           146:     int s;
        !           147:     struct in_addr in;
        !           148:     struct sockaddr_in addr;
        !           149:     int opt;
        !           150: 
        !           151:     s = socket(PF_INET, SOCK_STREAM, 0);
        !           152:     if (s == -1) {
        !           153:         return -1;
        !           154:     }
        !           155: 
        !           156:     if (inet_aton(address, &in) == 0) {
        !           157:         struct hostent *ent;
        !           158: 
        !           159:         ent = gethostbyname(address);
        !           160:         if (ent == NULL) {
        !           161:             goto error;
        !           162:         }
        !           163: 
        !           164:         memcpy(&in, ent->h_addr, sizeof(in));
        !           165:     }
        !           166: 
        !           167:     addr.sin_family = AF_INET;
        !           168:     addr.sin_port = htons(port);
        !           169:     memcpy(&addr.sin_addr.s_addr, &in, sizeof(in));
        !           170: 
        !           171:     opt = 1;
        !           172:     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
        !           173:         goto error;
        !           174:     }
        !           175: 
        !           176:     if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        !           177:         goto error;
        !           178:     }
        !           179: 
        !           180:     if (listen(s, 128) == -1) {
        !           181:         goto error;
        !           182:     }
        !           183: 
        !           184:     return s;
        !           185: error:
        !           186:     closesocket(s);
        !           187:     return -1;
        !           188: }
        !           189: 
        !           190: #ifndef _WIN32
        !           191: int unix_socket_incoming(const char *path)
        !           192: {
        !           193:     int s;
        !           194:     struct sockaddr_un addr;
        !           195: 
        !           196:     s = socket(PF_UNIX, SOCK_STREAM, 0);
        !           197:     if (s == -1) {
        !           198:         return -1;
        !           199:     }
        !           200: 
        !           201:     memset(&addr, 0, sizeof(addr));
        !           202:     addr.sun_family = AF_UNIX;
        !           203:     pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
        !           204: 
        !           205:     if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        !           206:         goto error;
        !           207:     }
        !           208: 
        !           209:     if (listen(s, 128) == -1) {
        !           210:         goto error;
        !           211:     }
        !           212: 
        !           213:     return s;
        !           214: error:
        !           215:     closesocket(s);
        !           216:     return -1;
        !           217: }
        !           218: 
        !           219: int unix_socket_outgoing(const char *path)
        !           220: {
        !           221:     int s;
        !           222:     struct sockaddr_un addr;
        !           223: 
        !           224:     s = socket(PF_UNIX, SOCK_STREAM, 0);
        !           225:     if (s == -1) {
        !           226:         return -1;
        !           227:     }
        !           228: 
        !           229:     memset(&addr, 0, sizeof(addr));
        !           230:     addr.sun_family = AF_UNIX;
        !           231:     pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
        !           232: 
        !           233:     if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        !           234:         goto error;
        !           235:     }
        !           236: 
        !           237:     return s;
        !           238: error:
        !           239:     closesocket(s);
        !           240:     return -1;
        !           241: }
        !           242: #else
        !           243: int unix_socket_incoming(const char *path)
        !           244: {
        !           245:     errno = ENOTSUP;
        !           246:     return -1;
        !           247: }
        !           248: 
        !           249: int unix_socket_outgoing(const char *path)
        !           250: {
        !           251:     errno = ENOTSUP;
        !           252:     return -1;
        !           253: }
        !           254: #endif
        !           255: 
        !           256: 
        !           257: /* Basic flow
        !           258: 
        !           259:    Server         Client
        !           260: 
        !           261:    Negotiate
        !           262:                   Request
        !           263:    Response
        !           264:                   Request
        !           265:    Response
        !           266:                   ...
        !           267:    ...
        !           268:                   Request (type == 2)
        !           269: */
        !           270: 
        !           271: int nbd_negotiate(int csock, off_t size)
        !           272: {
        !           273:        char buf[8 + 8 + 8 + 128];
        !           274: 
        !           275:        /* Negotiate
        !           276:           [ 0 ..   7]   passwd   ("NBDMAGIC")
        !           277:           [ 8 ..  15]   magic    (0x00420281861253)
        !           278:           [16 ..  23]   size
        !           279:           [24 .. 151]   reserved (0)
        !           280:         */
        !           281: 
        !           282:        TRACE("Beginning negotiation.");
        !           283:        memcpy(buf, "NBDMAGIC", 8);
        !           284:        cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
        !           285:        cpu_to_be64w((uint64_t*)(buf + 16), size);
        !           286:        memset(buf + 24, 0, 128);
        !           287: 
        !           288:        if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
        !           289:                LOG("write failed");
        !           290:                errno = EINVAL;
        !           291:                return -1;
        !           292:        }
        !           293: 
        !           294:        TRACE("Negotation succeeded.");
        !           295: 
        !           296:        return 0;
        !           297: }
        !           298: 
        !           299: int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
        !           300: {
        !           301:        char buf[8 + 8 + 8 + 128];
        !           302:        uint64_t magic;
        !           303: 
        !           304:        TRACE("Receiving negotation.");
        !           305: 
        !           306:        if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
        !           307:                LOG("read failed");
        !           308:                errno = EINVAL;
        !           309:                return -1;
        !           310:        }
        !           311: 
        !           312:        magic = be64_to_cpup((uint64_t*)(buf + 8));
        !           313:        *size = be64_to_cpup((uint64_t*)(buf + 16));
        !           314:        *blocksize = 1024;
        !           315: 
        !           316:        TRACE("Magic is %c%c%c%c%c%c%c%c",
        !           317:              qemu_isprint(buf[0]) ? buf[0] : '.',
        !           318:              qemu_isprint(buf[1]) ? buf[1] : '.',
        !           319:              qemu_isprint(buf[2]) ? buf[2] : '.',
        !           320:              qemu_isprint(buf[3]) ? buf[3] : '.',
        !           321:              qemu_isprint(buf[4]) ? buf[4] : '.',
        !           322:              qemu_isprint(buf[5]) ? buf[5] : '.',
        !           323:              qemu_isprint(buf[6]) ? buf[6] : '.',
        !           324:              qemu_isprint(buf[7]) ? buf[7] : '.');
        !           325:        TRACE("Magic is 0x%" PRIx64, magic);
        !           326:        TRACE("Size is %" PRIu64, *size);
        !           327: 
        !           328:        if (memcmp(buf, "NBDMAGIC", 8) != 0) {
        !           329:                LOG("Invalid magic received");
        !           330:                errno = EINVAL;
        !           331:                return -1;
        !           332:        }
        !           333: 
        !           334:        TRACE("Checking magic");
        !           335: 
        !           336:        if (magic != 0x00420281861253LL) {
        !           337:                LOG("Bad magic received");
        !           338:                errno = EINVAL;
        !           339:                return -1;
        !           340:        }
        !           341:         return 0;
        !           342: }
        !           343: 
        !           344: #ifndef _WIN32
        !           345: int nbd_init(int fd, int csock, off_t size, size_t blocksize)
        !           346: {
        !           347:        TRACE("Setting block size to %lu", (unsigned long)blocksize);
        !           348: 
        !           349:        if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
        !           350:                int serrno = errno;
        !           351:                LOG("Failed setting NBD block size");
        !           352:                errno = serrno;
        !           353:                return -1;
        !           354:        }
        !           355: 
        !           356:        TRACE("Setting size to %llu block(s)",
        !           357:              (unsigned long long)(size / blocksize));
        !           358: 
        !           359:        if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
        !           360:                int serrno = errno;
        !           361:                LOG("Failed setting size (in blocks)");
        !           362:                errno = serrno;
        !           363:                return -1;
        !           364:        }
        !           365: 
        !           366:        TRACE("Clearing NBD socket");
        !           367: 
        !           368:        if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
        !           369:                int serrno = errno;
        !           370:                LOG("Failed clearing NBD socket");
        !           371:                errno = serrno;
        !           372:                return -1;
        !           373:        }
        !           374: 
        !           375:        TRACE("Setting NBD socket");
        !           376: 
        !           377:        if (ioctl(fd, NBD_SET_SOCK, csock) == -1) {
        !           378:                int serrno = errno;
        !           379:                LOG("Failed to set NBD socket");
        !           380:                errno = serrno;
        !           381:                return -1;
        !           382:        }
        !           383: 
        !           384:        TRACE("Negotiation ended");
        !           385: 
        !           386:        return 0;
        !           387: }
        !           388: 
        !           389: int nbd_disconnect(int fd)
        !           390: {
        !           391:        ioctl(fd, NBD_CLEAR_QUE);
        !           392:        ioctl(fd, NBD_DISCONNECT);
        !           393:        ioctl(fd, NBD_CLEAR_SOCK);
        !           394:        return 0;
        !           395: }
        !           396: 
        !           397: int nbd_client(int fd, int csock)
        !           398: {
        !           399:        int ret;
        !           400:        int serrno;
        !           401: 
        !           402:        TRACE("Doing NBD loop");
        !           403: 
        !           404:        ret = ioctl(fd, NBD_DO_IT);
        !           405:        serrno = errno;
        !           406: 
        !           407:        TRACE("NBD loop returned %d: %s", ret, strerror(serrno));
        !           408: 
        !           409:        TRACE("Clearing NBD queue");
        !           410:        ioctl(fd, NBD_CLEAR_QUE);
        !           411: 
        !           412:        TRACE("Clearing NBD socket");
        !           413:        ioctl(fd, NBD_CLEAR_SOCK);
        !           414: 
        !           415:        errno = serrno;
        !           416:        return ret;
        !           417: }
        !           418: #else
        !           419: int nbd_init(int fd, int csock, off_t size, size_t blocksize)
        !           420: {
        !           421:     errno = ENOTSUP;
        !           422:     return -1;
        !           423: }
        !           424: 
        !           425: int nbd_disconnect(int fd)
        !           426: {
        !           427:     errno = ENOTSUP;
        !           428:     return -1;
        !           429: }
        !           430: 
        !           431: int nbd_client(int fd, int csock)
        !           432: {
        !           433:     errno = ENOTSUP;
        !           434:     return -1;
        !           435: }
        !           436: #endif
        !           437: 
        !           438: int nbd_send_request(int csock, struct nbd_request *request)
        !           439: {
        !           440:        uint8_t buf[4 + 4 + 8 + 8 + 4];
        !           441: 
        !           442:        cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
        !           443:        cpu_to_be32w((uint32_t*)(buf + 4), request->type);
        !           444:        cpu_to_be64w((uint64_t*)(buf + 8), request->handle);
        !           445:        cpu_to_be64w((uint64_t*)(buf + 16), request->from);
        !           446:        cpu_to_be32w((uint32_t*)(buf + 24), request->len);
        !           447: 
        !           448:        TRACE("Sending request to client");
        !           449: 
        !           450:        if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
        !           451:                LOG("writing to socket failed");
        !           452:                errno = EINVAL;
        !           453:                return -1;
        !           454:        }
        !           455:        return 0;
        !           456: }
        !           457: 
        !           458: 
        !           459: static int nbd_receive_request(int csock, struct nbd_request *request)
        !           460: {
        !           461:        uint8_t buf[4 + 4 + 8 + 8 + 4];
        !           462:        uint32_t magic;
        !           463: 
        !           464:        if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
        !           465:                LOG("read failed");
        !           466:                errno = EINVAL;
        !           467:                return -1;
        !           468:        }
        !           469: 
        !           470:        /* Request
        !           471:           [ 0 ..  3]   magic   (NBD_REQUEST_MAGIC)
        !           472:           [ 4 ..  7]   type    (0 == READ, 1 == WRITE)
        !           473:           [ 8 .. 15]   handle
        !           474:           [16 .. 23]   from
        !           475:           [24 .. 27]   len
        !           476:         */
        !           477: 
        !           478:        magic = be32_to_cpup((uint32_t*)buf);
        !           479:        request->type  = be32_to_cpup((uint32_t*)(buf + 4));
        !           480:        request->handle = be64_to_cpup((uint64_t*)(buf + 8));
        !           481:        request->from  = be64_to_cpup((uint64_t*)(buf + 16));
        !           482:        request->len   = be32_to_cpup((uint32_t*)(buf + 24));
        !           483: 
        !           484:        TRACE("Got request: "
        !           485:              "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
        !           486:              magic, request->type, request->from, request->len);
        !           487: 
        !           488:        if (magic != NBD_REQUEST_MAGIC) {
        !           489:                LOG("invalid magic (got 0x%x)", magic);
        !           490:                errno = EINVAL;
        !           491:                return -1;
        !           492:        }
        !           493:        return 0;
        !           494: }
        !           495: 
        !           496: int nbd_receive_reply(int csock, struct nbd_reply *reply)
        !           497: {
        !           498:        uint8_t buf[4 + 4 + 8];
        !           499:        uint32_t magic;
        !           500: 
        !           501:        memset(buf, 0xAA, sizeof(buf));
        !           502: 
        !           503:        if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
        !           504:                LOG("read failed");
        !           505:                errno = EINVAL;
        !           506:                return -1;
        !           507:        }
        !           508: 
        !           509:        /* Reply
        !           510:           [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
        !           511:           [ 4 ..  7]    error   (0 == no error)
        !           512:           [ 7 .. 15]    handle
        !           513:         */
        !           514: 
        !           515:        magic = be32_to_cpup((uint32_t*)buf);
        !           516:        reply->error  = be32_to_cpup((uint32_t*)(buf + 4));
        !           517:        reply->handle = be64_to_cpup((uint64_t*)(buf + 8));
        !           518: 
        !           519:        TRACE("Got reply: "
        !           520:              "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }",
        !           521:              magic, reply->error, reply->handle);
        !           522: 
        !           523:        if (magic != NBD_REPLY_MAGIC) {
        !           524:                LOG("invalid magic (got 0x%x)", magic);
        !           525:                errno = EINVAL;
        !           526:                return -1;
        !           527:        }
        !           528:        return 0;
        !           529: }
        !           530: 
        !           531: static int nbd_send_reply(int csock, struct nbd_reply *reply)
        !           532: {
        !           533:        uint8_t buf[4 + 4 + 8];
        !           534: 
        !           535:        /* Reply
        !           536:           [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
        !           537:           [ 4 ..  7]    error   (0 == no error)
        !           538:           [ 7 .. 15]    handle
        !           539:         */
        !           540:        cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
        !           541:        cpu_to_be32w((uint32_t*)(buf + 4), reply->error);
        !           542:        cpu_to_be64w((uint64_t*)(buf + 8), reply->handle);
        !           543: 
        !           544:        TRACE("Sending response to client");
        !           545: 
        !           546:        if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
        !           547:                LOG("writing to socket failed");
        !           548:                errno = EINVAL;
        !           549:                return -1;
        !           550:        }
        !           551:        return 0;
        !           552: }
        !           553: 
        !           554: int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
        !           555:              off_t *offset, bool readonly, uint8_t *data, int data_size)
        !           556: {
        !           557:        struct nbd_request request;
        !           558:        struct nbd_reply reply;
        !           559: 
        !           560:        TRACE("Reading request.");
        !           561: 
        !           562:        if (nbd_receive_request(csock, &request) == -1)
        !           563:                return -1;
        !           564: 
        !           565:        if (request.len > data_size) {
        !           566:                LOG("len (%u) is larger than max len (%u)",
        !           567:                    request.len, data_size);
        !           568:                errno = EINVAL;
        !           569:                return -1;
        !           570:        }
        !           571: 
        !           572:        if ((request.from + request.len) < request.from) {
        !           573:                LOG("integer overflow detected! "
        !           574:                    "you're probably being attacked");
        !           575:                errno = EINVAL;
        !           576:                return -1;
        !           577:        }
        !           578: 
        !           579:        if ((request.from + request.len) > size) {
        !           580:                LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
        !           581:                    ", Offset: %" PRIu64 "\n",
        !           582:                     request.from, request.len, size, dev_offset);
        !           583:                LOG("requested operation past EOF--bad client?");
        !           584:                errno = EINVAL;
        !           585:                return -1;
        !           586:        }
        !           587: 
        !           588:        TRACE("Decoding type");
        !           589: 
        !           590:        reply.handle = request.handle;
        !           591:        reply.error = 0;
        !           592: 
        !           593:        switch (request.type) {
        !           594:        case NBD_CMD_READ:
        !           595:                TRACE("Request type is READ");
        !           596: 
        !           597:                if (bdrv_read(bs, (request.from + dev_offset) / 512, data,
        !           598:                              request.len / 512) == -1) {
        !           599:                        LOG("reading from file failed");
        !           600:                        errno = EINVAL;
        !           601:                        return -1;
        !           602:                }
        !           603:                *offset += request.len;
        !           604: 
        !           605:                TRACE("Read %u byte(s)", request.len);
        !           606: 
        !           607:                if (nbd_send_reply(csock, &reply) == -1)
        !           608:                        return -1;
        !           609: 
        !           610:                TRACE("Sending data to client");
        !           611: 
        !           612:                if (write_sync(csock, data, request.len) != request.len) {
        !           613:                        LOG("writing to socket failed");
        !           614:                        errno = EINVAL;
        !           615:                        return -1;
        !           616:                }
        !           617:                break;
        !           618:        case NBD_CMD_WRITE:
        !           619:                TRACE("Request type is WRITE");
        !           620: 
        !           621:                TRACE("Reading %u byte(s)", request.len);
        !           622: 
        !           623:                if (read_sync(csock, data, request.len) != request.len) {
        !           624:                        LOG("reading from socket failed");
        !           625:                        errno = EINVAL;
        !           626:                        return -1;
        !           627:                }
        !           628: 
        !           629:                if (readonly) {
        !           630:                        TRACE("Server is read-only, return error");
        !           631:                        reply.error = 1;
        !           632:                } else {
        !           633:                        TRACE("Writing to device");
        !           634: 
        !           635:                        if (bdrv_write(bs, (request.from + dev_offset) / 512,
        !           636:                                       data, request.len / 512) == -1) {
        !           637:                                LOG("writing to file failed");
        !           638:                                errno = EINVAL;
        !           639:                                return -1;
        !           640:                        }
        !           641: 
        !           642:                        *offset += request.len;
        !           643:                }
        !           644: 
        !           645:                if (nbd_send_reply(csock, &reply) == -1)
        !           646:                        return -1;
        !           647:                break;
        !           648:        case NBD_CMD_DISC:
        !           649:                TRACE("Request type is DISCONNECT");
        !           650:                errno = 0;
        !           651:                return 1;
        !           652:        default:
        !           653:                LOG("invalid request type (%u) received", request.type);
        !           654:                errno = EINVAL;
        !           655:                return -1;
        !           656:        }
        !           657: 
        !           658:        TRACE("Request/Reply complete");
        !           659: 
        !           660:        return 0;
        !           661: }

unix.superglobalmegacorp.com