Depend on the nbd module being loaded
[nbd.git] / nbd-client.c
blobf4e120f84fa6ad10ed46f44de1fbbd2970f91429
1 /*
2 * Open connection for network block device
4 * Copyright 1997,1998 Pavel Machek, distribute under GPL
5 * <pavel@atrey.karlin.mff.cuni.cz>
6 * Copyright (c) 2002 - 2011 Wouter Verhelst <w@uter.be>
8 * Version 1.0 - 64bit issues should be fixed, now
9 * Version 1.1 - added bs (blocksize) option (Alexey Guzeev, aga@permonline.ru)
10 * Version 1.2 - I added new option '-d' to send the disconnect request
11 * Version 2.0 - Version synchronised with server
12 * Version 2.1 - Check for disconnection before INIT_PASSWD is received
13 * to make errormsg a bit more helpful in case the server can't
14 * open the exported file.
15 * 16/03/2010 - Add IPv6 support.
16 * Kitt Tientanopajai <kitt@kitty.in.th>
17 * Neutron Soutmun <neo.neutron@gmail.com>
18 * Suriya Soutmun <darksolar@gmail.com>
21 #include "config.h"
22 #include "lfs.h"
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <netinet/tcp.h>
30 #include <netinet/in.h>
31 #include <netdb.h>
32 #include "netdb-compat.h"
33 #include <inttypes.h>
34 #include <stdio.h>
35 #include <fcntl.h>
36 #include <syslog.h>
37 #include <stdlib.h>
38 #include <sys/mount.h>
39 #include <sys/mman.h>
40 #include <signal.h>
41 #include <errno.h>
42 #include <getopt.h>
43 #include <stdarg.h>
44 #include <stdbool.h>
45 #include <time.h>
47 #include <linux/ioctl.h>
49 #if HAVE_NETLINK
50 #include "nbd-netlink.h"
51 #include <netlink/netlink.h>
52 #include <netlink/genl/genl.h>
53 #include <netlink/genl/ctrl.h>
54 #endif
56 #define MY_NAME "nbd_client"
57 #include "cliserv.h"
59 #if HAVE_GNUTLS && !defined(NOTLS)
60 #include "crypto-gnutls.h"
61 #endif
63 #include "nbdclt.h"
64 #include "nbdtab_parser.tab.h"
66 CLIENT* cur_client;
67 extern FILE *yyin, *yyout;
68 bool found_config = false;
69 bool parse_error = false;
71 #define SET_PROP(str, member, rval) if(!strcmp(property, str)) { cur_client->member = (rval); return; }
72 void nbdtab_set_property(char *property, char *val) {
73 if(found_config) return;
74 SET_PROP("port", port, val);
75 SET_PROP("certfile", cert, val);
76 SET_PROP("keyfile", key, val);
77 SET_PROP("cacertfile", cacert, val);
78 SET_PROP("tlshostname", tlshostn, val);
79 SET_PROP("priority", priority, val);
80 SET_PROP("bs", bs, strtol(val, NULL, 10));
81 SET_PROP("timeout", timeout, strtol(val, NULL, 10));
82 SET_PROP("conns", nconn, strtol(val, NULL, 10));
83 if(*property != '_') {
84 fprintf(stderr, "Warning: unknown option '%s' found in nbdtab file", property);
87 #undef SET_PROP
89 #define SET_FLAG(str, member) if(!strcmp(property, str)) { cur_client->member = true; return; }
90 void nbdtab_set_flag(char *property) {
91 if(found_config) return;
92 SET_FLAG("no_optgo", no_optgo);
93 SET_FLAG("persist", persist);
94 SET_FLAG("swap", swap);
95 SET_FLAG("unix", b_unix);
96 SET_FLAG("preinit", preinit);
97 SET_FLAG("tls", tls);
98 if(*property != '_') {
99 fprintf(stderr, "Warning: unknown option '%s' found in nbdtab file", property);
103 void nbdtab_commit_line(char *devn, char *hostn, char *exportname) {
104 if(!strncmp(devn, "/dev/", 5)) {
105 devn += 5;
107 if(!strcmp(cur_client->dev, devn)) {
108 found_config = true;
109 cur_client->hostn = hostn;
110 cur_client->name = exportname;
111 } else {
112 if(!found_config) {
113 char *tmp = cur_client->dev;
114 memset(cur_client, 0, sizeof(CLIENT));
115 cur_client->bs = 512;
116 cur_client->nconn = 1;
117 cur_client->dev = tmp;
120 return;
123 void yyerror(char *msg) {
124 parse_error = true;
125 fprintf(stderr, "parse error parsing " SYSCONFDIR "/nbdtab: %s", msg);
128 #undef SET_FLAG
130 #define NBDC_DO_LIST 1
132 #if HAVE_NETLINK
133 static int callback(struct nl_msg *msg, void *arg) {
134 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
135 struct nlattr *msg_attr[NBD_ATTR_MAX + 1];
136 int ret;
137 uint32_t index;
139 ret = nla_parse(msg_attr, NBD_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
140 genlmsg_attrlen(gnlh, 0), NULL);
141 if (ret)
142 err("Invalid response from the kernel\n");
143 if (!msg_attr[NBD_ATTR_INDEX])
144 err("Did not receive index from the kernel\n");
145 index = nla_get_u32(msg_attr[NBD_ATTR_INDEX]);
146 printf("Connected /dev/nbd%d\n", (int)index);
147 return NL_OK;
150 static struct nl_sock *get_nbd_socket(int *driver_id) {
151 struct nl_sock *socket;
153 socket = nl_socket_alloc();
154 if (!socket)
155 err("Couldn't allocate netlink socket\n");
157 if (genl_connect(socket))
158 err("Couldn't connect to the generic netlink socket\n");
159 *driver_id = genl_ctrl_resolve(socket, "nbd");
160 if (*driver_id < 0)
161 err("Couldn't resolve the nbd netlink family, make sure the nbd module is loaded and your nbd driver supports the netlink interface.\n");
162 return socket;
165 static void netlink_configure(int index, int *sockfds, int num_connects,
166 u64 size64, int blocksize, uint16_t flags,
167 int timeout) {
168 struct nl_sock *socket;
169 struct nlattr *sock_attr;
170 struct nl_msg *msg;
171 int driver_id, i;
173 socket = get_nbd_socket(&driver_id);
174 nl_socket_modify_cb(socket, NL_CB_VALID, NL_CB_CUSTOM, callback, NULL);
176 msg = nlmsg_alloc();
177 if (!msg)
178 err("Couldn't allocate netlink message\n");
179 genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, driver_id, 0, 0,
180 NBD_CMD_CONNECT, 0);
181 if (index >= 0)
182 NLA_PUT_U32(msg, NBD_ATTR_INDEX, index);
183 NLA_PUT_U64(msg, NBD_ATTR_SIZE_BYTES, size64);
184 NLA_PUT_U64(msg, NBD_ATTR_BLOCK_SIZE_BYTES, blocksize);
185 NLA_PUT_U64(msg, NBD_ATTR_SERVER_FLAGS, flags);
186 if (timeout)
187 NLA_PUT_U64(msg, NBD_ATTR_TIMEOUT, timeout);
189 sock_attr = nla_nest_start(msg, NBD_ATTR_SOCKETS);
190 if (!sock_attr)
191 err("Couldn't nest the sockets for our connection\n");
192 for (i = 0; i < num_connects; i++) {
193 struct nlattr *sock_opt;
194 sock_opt = nla_nest_start(msg, NBD_SOCK_ITEM);
195 if (!sock_opt)
196 err("Couldn't nest the sockets for our connection\n");
197 NLA_PUT_U32(msg, NBD_SOCK_FD, sockfds[i]);
198 nla_nest_end(msg, sock_opt);
200 nla_nest_end(msg, sock_attr);
202 if (nl_send_sync(socket, msg) < 0)
203 err("Failed to setup device, check dmesg\n");
204 return;
205 nla_put_failure:
206 err("Failed to create netlink message\n");
209 static void netlink_disconnect(char *nbddev) {
210 struct nl_sock *socket;
211 struct nl_msg *msg;
212 int driver_id;
214 int index = -1;
215 if (nbddev) {
216 if (sscanf(nbddev, "/dev/nbd%d", &index) != 1)
217 err("Invalid nbd device target\n");
219 if (index < 0)
220 err("Invalid nbd device target\n");
222 socket = get_nbd_socket(&driver_id);
224 msg = nlmsg_alloc();
225 if (!msg)
226 err("Couldn't allocate netlink message\n");
227 genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, driver_id, 0, 0,
228 NBD_CMD_DISCONNECT, 0);
229 NLA_PUT_U32(msg, NBD_ATTR_INDEX, index);
230 if (nl_send_sync(socket, msg) < 0)
231 err("Failed to disconnect device, check dmsg\n");
232 nl_socket_free(socket);
233 return;
234 nla_put_failure:
235 err("Failed to create netlink message\n");
237 #else
238 static void netlink_configure(int index, int *sockfds, int num_connects,
239 u64 size64, int blocksize, uint16_t flags,
240 int timeout)
244 static void netlink_disconnect(char *nbddev)
247 #endif /* HAVE_NETLINK */
249 int check_conn(char* devname, int do_print) {
250 char buf[256];
251 char* p;
252 int fd;
253 int len;
255 if( (p=strrchr(devname, '/')) ) {
256 devname=p+1;
258 if((p=strchr(devname, 'p'))) {
259 /* We can't do checks on partitions. */
260 *p='\0';
262 snprintf(buf, 256, "/sys/block/%s/pid", devname);
263 if((fd=open(buf, O_RDONLY))<0) {
264 if(errno==ENOENT) {
265 return 1;
266 } else {
267 return 2;
270 len=read(fd, buf, 256);
271 if(len < 0) {
272 perror("could not read from server");
273 close(fd);
274 return 2;
276 buf[(len < 256) ? len : 255]='\0';
277 if(do_print) printf("%s\n", buf);
278 close(fd);
279 return 0;
282 int opennet(char *name, char* portstr) {
283 int sock;
284 struct addrinfo hints;
285 struct addrinfo *ai = NULL;
286 struct addrinfo *rp = NULL;
287 int e;
289 memset(&hints,'\0',sizeof(hints));
290 hints.ai_family = AF_UNSPEC;
291 hints.ai_socktype = SOCK_STREAM;
292 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
293 hints.ai_protocol = IPPROTO_TCP;
295 e = getaddrinfo(name, portstr, &hints, &ai);
297 if(e != 0) {
298 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
299 freeaddrinfo(ai);
300 return -1;
303 for(rp = ai; rp != NULL; rp = rp->ai_next) {
304 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
306 if(sock == -1)
307 continue; /* error */
309 if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
310 break; /* success */
312 close(sock);
315 if (rp == NULL) {
316 err_nonfatal("Socket failed: %m");
317 sock = -1;
318 goto err;
321 setmysockopt(sock);
322 err:
323 freeaddrinfo(ai);
324 return sock;
327 int openunix(const char *path) {
328 int sock;
329 struct sockaddr_un un_addr;
330 memset(&un_addr, 0, sizeof(un_addr));
332 un_addr.sun_family = AF_UNIX;
333 if (strnlen(path, sizeof(un_addr.sun_path)) == sizeof(un_addr.sun_path)) {
334 err_nonfatal("UNIX socket path too long");
335 return -1;
338 strncpy(un_addr.sun_path, path, sizeof(un_addr.sun_path) - 1);
340 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
341 err_nonfatal("SOCKET failed");
342 return -1;
345 if (connect(sock, &un_addr, sizeof(un_addr)) == -1) {
346 err_nonfatal("CONNECT failed");
347 close(sock);
348 return -1;
350 return sock;
353 void send_request(int sock, uint32_t opt, ssize_t datasize, void* data) {
354 struct {
355 uint64_t magic;
356 uint32_t opt;
357 uint32_t datasize;
358 } __attribute__((packed)) header = {
359 ntohll(opts_magic),
360 ntohl(opt),
361 ntohl(datasize),
363 if(datasize < 0) {
364 datasize = strlen((char*)data);
365 header.datasize = htonl(datasize);
367 writeit(sock, &header, sizeof(header));
368 if(data != NULL) {
369 writeit(sock, data, datasize);
373 void send_info_request(int sock, uint32_t opt, int n_reqs, uint16_t* reqs, char* name) {
374 uint16_t rlen = htons(n_reqs);
375 uint32_t nlen = htonl(strlen(name));
377 send_request(sock, opt, sizeof(uint32_t) + strlen(name) + sizeof(uint16_t) + n_reqs * sizeof(uint16_t), NULL);
378 writeit(sock, &nlen, sizeof(nlen));
379 writeit(sock, name, strlen(name));
380 writeit(sock, &rlen, sizeof(rlen));
381 if(n_reqs > 0) {
382 writeit(sock, reqs, n_reqs * sizeof(uint16_t));
386 struct reply {
387 uint64_t magic;
388 uint32_t opt;
389 uint32_t reply_type;
390 uint32_t datasize;
391 char data[];
392 } __attribute__((packed));
394 struct reply* read_reply(int sock) {
395 struct reply *retval = malloc(sizeof(struct reply));
397 if (retval == NULL)
398 return NULL;
400 if(readit(sock, retval, sizeof(*retval)) < 0) {
401 free(retval);
402 return NULL;
405 retval->magic = ntohll(retval->magic);
406 retval->opt = ntohl(retval->opt);
407 retval->reply_type = ntohl(retval->reply_type);
408 retval->datasize = ntohl(retval->datasize);
409 if (retval->magic != rep_magic) {
410 fprintf(stderr, "E: received invalid negotiation magic %" PRIu64 " (expected %" PRIu64 ")", retval->magic, rep_magic);
411 exit(EXIT_FAILURE);
413 if (retval->datasize > 0 && retval->datasize < 4096) {
414 struct reply *retval_r = realloc(retval, sizeof(struct reply) + retval->datasize);
415 if (retval_r == NULL) {
416 free(retval);
417 return NULL;
419 retval = retval_r;
420 readit(sock, &(retval->data), retval->datasize);
422 return retval;
425 void ask_list(int sock) {
426 uint32_t opt_server;
427 uint32_t len;
428 uint32_t lenn;
429 uint32_t reptype;
430 uint64_t magic;
431 int rlen;
432 const int BUF_SIZE = 1024;
433 char buf[BUF_SIZE];
435 send_request(sock, NBD_OPT_LIST, 0, NULL);
436 /* newline, move away from the "Negotiation:" line */
437 printf("\n");
438 do {
439 memset(buf, 0, 1024);
440 if(read(sock, &magic, sizeof(magic)) < 0) {
441 err("Reading magic from server: %m");
443 if(read(sock, &opt_server, sizeof(opt_server)) < 0) {
444 err("Reading option: %m");
446 if(read(sock, &reptype, sizeof(reptype)) <0) {
447 err("Reading reply from server: %m");
449 if(read(sock, &len, sizeof(len)) < 0) {
450 err("Reading length from server: %m");
452 magic=ntohll(magic);
453 len=ntohl(len);
454 reptype=ntohl(reptype);
455 if(magic != rep_magic) {
456 err("Not enough magic from server");
458 if(reptype & NBD_REP_FLAG_ERROR) {
459 switch(reptype) {
460 case NBD_REP_ERR_POLICY:
461 fprintf(stderr, "\nE: listing not allowed by server.\n");
462 break;
463 default:
464 fprintf(stderr, "\nE: unexpected error from server.\n");
465 break;
467 if(len > 0 && len < BUF_SIZE) {
468 if((rlen=read(sock, buf, len)) < 0) {
469 fprintf(stderr, "\nE: could not read error message from server\n");
470 } else {
471 buf[rlen] = '\0';
472 fprintf(stderr, "Server said: %s\n", buf);
475 exit(EXIT_FAILURE);
476 } else {
477 if(reptype != NBD_REP_ACK) {
478 if(reptype != NBD_REP_SERVER) {
479 err("Server sent us a reply we don't understand!");
481 if(read(sock, &lenn, sizeof(lenn)) < 0) {
482 fprintf(stderr, "\nE: could not read export name length from server\n");
483 exit(EXIT_FAILURE);
485 lenn=ntohl(lenn);
486 if (lenn >= BUF_SIZE) {
487 fprintf(stderr, "\nE: export name on server too long\n");
488 exit(EXIT_FAILURE);
490 if(read(sock, buf, lenn) < 0) {
491 fprintf(stderr, "\nE: could not read export name from server\n");
492 exit(EXIT_FAILURE);
494 buf[lenn] = 0;
495 printf("%s", buf);
496 len -= lenn;
497 len -= sizeof(lenn);
498 if(len > 0) {
499 if(len >= BUF_SIZE) {
500 fprintf(stderr, "\nE: export description read buffer overflow\n");
501 exit(EXIT_FAILURE);
503 if(read(sock, buf, len) < 0) {
504 fprintf(stderr, "\nE: could not read export description from server\n");
505 exit(EXIT_FAILURE);
507 buf[len] = 0;
508 printf(": %s\n", buf);
509 } else {
510 printf("\n");
514 } while(reptype != NBD_REP_ACK);
515 send_request(sock, NBD_OPT_ABORT, 0, NULL);
518 void parse_sizes(char *buf, uint64_t *size, uint16_t *flags) {
519 memcpy(size, buf, sizeof(*size));
520 *size = ntohll(*size);
521 buf += sizeof(*size);
522 memcpy(flags, buf, sizeof(*flags));
523 *flags = ntohs(*flags);
525 if ((*size>>12) > (uint64_t)~0UL) {
526 printf("size = %luMB", (unsigned long)(*size>>20));
527 err("Exported device is too big for me. Get 64-bit machine :-(\n");
528 } else {
529 printf("size = %luMB", (unsigned long)(*size>>20));
531 printf("\n");
534 void send_opt_exportname(int sock, u64 *rsize64, uint16_t *flags, bool can_opt_go, char* name, uint16_t global_flags) {
535 send_request(sock, NBD_OPT_EXPORT_NAME, -1, name);
536 char b[sizeof(*flags) + sizeof(*rsize64)];
537 if(readit(sock, b, sizeof(b)) < 0 && can_opt_go) {
538 err("E: server does not support NBD_OPT_GO and dropped connection after sending NBD_OPT_EXPORT_NAME. Try -g.");
540 parse_sizes(b, rsize64, flags);
541 if(!(global_flags & NBD_FLAG_NO_ZEROES)) {
542 char buf[125];
543 readit(sock, buf, 124);
547 void negotiate(int *sockp, u64 *rsize64, uint16_t *flags, char* name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts, char *certfile, char *keyfile, char *cacertfile, char *tlshostname, bool tls, char *priority, bool can_opt_go) {
548 u64 magic;
549 uint16_t tmp;
550 uint16_t global_flags;
551 char buf[256] = "\0\0\0\0\0\0\0\0\0";
552 int sock = *sockp;
554 printf("Negotiation: ");
555 readit(sock, buf, 8);
556 if (strcmp(buf, INIT_PASSWD))
557 err("INIT_PASSWD bad");
558 printf(".");
559 readit(sock, &magic, sizeof(magic));
560 magic = ntohll(magic);
561 if (magic != opts_magic) {
562 if(magic == cliserv_magic) {
563 err("It looks like you're trying to connect to an oldstyle server. This is no longer supported since nbd 3.10.");
566 printf(".");
567 readit(sock, &tmp, sizeof(uint16_t));
568 global_flags = ntohs(tmp);
569 if((needed_flags & global_flags) != needed_flags) {
570 /* There's currently really only one reason why this
571 * check could possibly fail, but we may need to change
572 * this error message in the future... */
573 fprintf(stderr, "\nE: Server does not support listing exports\n");
574 exit(EXIT_FAILURE);
577 if (global_flags & NBD_FLAG_NO_ZEROES) {
578 client_flags |= NBD_FLAG_C_NO_ZEROES;
580 client_flags = htonl(client_flags);
581 if (write(sock, &client_flags, sizeof(client_flags)) < 0)
582 err("Failed/2.1: %m");
584 #if HAVE_GNUTLS && !defined(NOTLS)
585 /* TLS */
586 if (tls) {
587 int plainfd[2]; // [0] is used by the proxy, [1] is used by NBD
588 tlssession_t *s = NULL;
589 int ret;
590 uint32_t tmp32;
591 uint64_t tmp64;
593 send_request(sock, NBD_OPT_STARTTLS, 0, NULL);
595 if (read(sock, &tmp64, sizeof(tmp64)) < 0)
596 err("Could not read cliserv_magic: %m");
597 tmp64 = ntohll(tmp64);
598 if (tmp64 != NBD_OPT_REPLY_MAGIC) {
599 err("reply magic does not match");
601 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
602 err("Could not read option type: %m");
603 tmp32 = ntohl(tmp32);
604 if (tmp32 != NBD_OPT_STARTTLS)
605 err("Reply to wrong option");
606 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
607 err("Could not read option reply type: %m");
608 tmp32 = ntohl(tmp32);
609 if (tmp32 != NBD_REP_ACK) {
610 err("Option reply type != NBD_REP_ACK");
612 if (read(sock, &tmp32, sizeof(tmp32)) < 0) err(
613 "Could not read option data length: %m");
614 tmp32 = ntohl(tmp32);
615 if (tmp32 != 0) {
616 err("Option reply data length != 0");
618 s = tlssession_new(0,
619 keyfile,
620 certfile,
621 cacertfile,
622 tlshostname,
623 priority,
624 !cacertfile || !tlshostname, // insecure flag
625 #ifdef DODBG
626 1, // debug
627 #else
628 0, // debug
629 #endif
630 NULL, // quitfn
631 NULL, // erroutfn
632 NULL // opaque
634 if (!s)
635 err("Cannot establish TLS session");
637 if (socketpair(AF_UNIX, SOCK_STREAM, 0, plainfd) < 0)
638 err("Cannot get socket pair");
640 if (set_nonblocking(plainfd[0], 0) <0 ||
641 set_nonblocking(plainfd[1], 0) <0 ||
642 set_nonblocking(sock, 0) <0) {
643 close(plainfd[0]);
644 close(plainfd[1]);
645 err("Cannot set socket options");
648 ret = fork();
649 if (ret < 0)
650 err("Could not fork");
651 else if (ret == 0) {
652 // we are the child
653 if (daemon(0, 0) < 0) {
654 /* no one will see this */
655 fprintf(stderr, "Can't detach from the terminal");
656 exit(1);
658 signal (SIGPIPE, SIG_IGN);
659 close(plainfd[1]);
660 tlssession_mainloop(sock, plainfd[0], s);
661 close(sock);
662 close(plainfd[0]);
663 exit(0);
665 close(plainfd[0]);
666 close(sock);
667 sock = plainfd[1]; /* use the decrypted FD from now on */
668 *sockp = sock;
670 #else
671 if (keyfile) {
672 err("TLS requested but support not compiled in");
674 #endif
676 if(do_opts & NBDC_DO_LIST) {
677 ask_list(sock);
678 exit(EXIT_SUCCESS);
681 struct reply *rep = NULL;
683 if(!can_opt_go) {
684 send_opt_exportname(sock, rsize64, flags, can_opt_go, name, global_flags);
685 return;
688 send_info_request(sock, NBD_OPT_GO, 0, NULL, name);
690 do {
691 if(rep != NULL) free(rep);
692 rep = read_reply(sock);
693 if(rep == NULL) {
694 err("Unable to read reply.");
695 exit(EXIT_FAILURE);
697 if(rep->reply_type & NBD_REP_FLAG_ERROR) {
698 switch(rep->reply_type) {
699 case NBD_REP_ERR_UNSUP:
700 /* server doesn't support NBD_OPT_GO or NBD_OPT_INFO,
701 * fall back to NBD_OPT_EXPORT_NAME */
702 send_opt_exportname(sock, rsize64, flags, can_opt_go, name, global_flags);
703 free(rep);
704 return;
705 case NBD_REP_ERR_POLICY:
706 if(rep->datasize > 0) {
707 char errstr[1024];
708 rep->data[rep->datasize - 1] = '\0';
709 snprintf(errstr, sizeof errstr, "Connection not allowed by server policy. Server said: %s", rep->data);
710 err(errstr);
711 } else {
712 err("Connection not allowed by server policy.");
714 free(rep);
715 exit(EXIT_FAILURE);
716 default:
717 if(rep->datasize > 0) {
718 char errstr[1024];
719 rep->data[rep->datasize - 1] = '\0';
720 snprintf(errstr, sizeof errstr, "Unknown error returned by server. Server said: %s", rep->data);
721 err(errstr);
722 } else {
723 err("Unknown error returned by server.");
725 free(rep);
726 exit(EXIT_FAILURE);
729 uint16_t info_type;
730 switch(rep->reply_type) {
731 case NBD_REP_INFO:
732 memcpy(&info_type, rep->data, 2);
733 info_type = htons(info_type);
734 switch(info_type) {
735 case NBD_INFO_EXPORT:
736 parse_sizes(rep->data + 2, rsize64, flags);
737 break;
738 default:
739 // ignore these, don't need them
740 break;
742 break;
743 case NBD_REP_ACK:
744 break;
745 default:
746 err_nonfatal("Unknown reply to NBD_OPT_GO received, ignoring");
748 } while(rep->reply_type != NBD_REP_ACK);
749 free(rep);
752 bool get_from_config(char* cfgname, char** name_ptr, char** dev_ptr, char** hostn_ptr, int* bs, int* timeout, int* persist, int* swap, int* b_unix, char**port, int* num_conns, char **certfile, char **keyfile, char **cacertfile, char **tlshostname, char **priority, bool *can_opt_go) {
753 bool retval = false;
754 cur_client = calloc(sizeof(CLIENT), 1);
755 cur_client->bs = 512;
756 cur_client->nconn = 1;
757 cur_client->port = NBD_DEFAULT_PORT;
758 yyin = fopen(SYSCONFDIR "/nbdtab", "r");
759 yyout = fopen("/dev/null", "w");
761 if(!strncmp(cfgname, "/dev/", 5)) {
762 cfgname += 5;
764 cur_client->dev = cfgname;
765 if(yyin == NULL) {
766 fprintf(stderr, "while opening %s: ", SYSCONFDIR "/nbdtab");
767 perror("could not open config file");
768 goto out;
770 yyparse();
772 if(!found_config || parse_error) {
773 goto out;
775 *name_ptr = cur_client->name;
776 *dev_ptr = calloc(strlen(cur_client->dev) + 6, 1);
777 if (!*dev_ptr) {
778 goto out;
780 snprintf(*dev_ptr, strlen(cur_client->dev) + 6, "/dev/%s", cur_client->dev);
781 *hostn_ptr = cur_client->hostn;
782 *bs = cur_client->bs;
783 *timeout = cur_client->timeout;
784 *persist = cur_client->persist ? 1 : 0;
785 *swap = cur_client->swap ? 1 : 0;
786 *b_unix = cur_client->b_unix ? 1 : 0;
787 *port = cur_client->port;
788 *num_conns = cur_client->nconn;
789 *certfile = cur_client->cert;
790 *keyfile = cur_client->key;
791 *cacertfile = cur_client->cacert;
792 *tlshostname = cur_client->tlshostn;
793 *priority = cur_client->priority;
794 *can_opt_go = !(cur_client->no_optgo);
796 retval = true;
797 out:
798 if(yyin != NULL) {
799 fclose(yyin);
801 if(yyout != NULL) {
802 fclose(yyout);
804 return retval;
807 void setsizes(int nbd, u64 size64, int blocksize, u32 flags) {
808 unsigned long size;
809 int read_only = (flags & NBD_FLAG_READ_ONLY) ? 1 : 0;
811 if (size64>>12 > (uint64_t)~0UL)
812 err("Device too large.\n");
813 else {
814 int tmp_blocksize = 4096;
815 if (size64 / (u64)blocksize <= (uint64_t)~0UL)
816 tmp_blocksize = blocksize;
817 if (ioctl(nbd, NBD_SET_BLKSIZE, tmp_blocksize) < 0) {
818 fprintf(stderr, "Failed to set blocksize %d\n",
819 tmp_blocksize);
820 err("Ioctl/1.1a failed: %m\n");
822 size = (unsigned long)(size64 / (u64)tmp_blocksize);
823 if (ioctl(nbd, NBD_SET_SIZE_BLOCKS, size) < 0)
824 err("Ioctl/1.1b failed: %m\n");
825 if (tmp_blocksize != blocksize) {
826 if (ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long)blocksize) < 0) {
827 fprintf(stderr, "Failed to set blocksize %d\n",
828 blocksize);
829 err("Ioctl/1.1c failed: %m\n");
832 fprintf(stderr, "bs=%d, sz=%" PRIu64 " bytes\n", blocksize, (u64)tmp_blocksize * size);
835 ioctl(nbd, NBD_CLEAR_SOCK);
837 /* ignore error as kernel may not support */
838 ioctl(nbd, NBD_SET_FLAGS, (unsigned long) flags);
840 if (ioctl(nbd, BLKROSET, (unsigned long) &read_only) < 0)
841 err("Unable to set read-only attribute for device");
844 void set_timeout(int nbd, int timeout) {
845 if (timeout) {
846 if (ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long)timeout) < 0)
847 err("Ioctl NBD_SET_TIMEOUT failed: %m\n");
848 fprintf(stderr, "timeout=%d\n", timeout);
852 void finish_sock(int sock, int nbd, int swap) {
853 if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) {
854 if (errno == EBUSY)
855 err("Kernel doesn't support multiple connections\n");
856 else
857 err("Ioctl NBD_SET_SOCK failed: %m\n");
860 #ifndef __ANDROID__
861 if (swap)
862 mlockall(MCL_CURRENT | MCL_FUTURE);
863 #endif
866 static int
867 oom_adjust(const char *file, const char *value)
869 int fd, rc;
870 size_t len;
872 fd = open(file, O_WRONLY);
873 if (fd < 0)
874 return -1;
875 len = strlen(value);
876 rc = write(fd, value, len) != (ssize_t) len;
877 close(fd);
878 return rc ? -1 : 0;
881 void usage(char* errmsg, ...) {
882 if(errmsg) {
883 char tmp[256];
884 va_list ap;
885 va_start(ap, errmsg);
886 snprintf(tmp, 256, "ERROR: %s\n\n", errmsg);
887 vfprintf(stderr, tmp, ap);
888 va_end(ap);
889 } else {
890 fprintf(stderr, "%s version %s\n", PROG_NAME, PACKAGE_VERSION);
892 #if HAVE_NETLINK
893 fprintf(stderr, "Usage: nbd-client -name|-N name host [port] nbd_device\n\t[-block-size|-b block size] [-timeout|-t timeout] [-swap|-s]\n\t[-persist|-p] [-nofork|-n] [-systemd-mark|-m] [-nonetlink|-L]\n\t[-readonly|-R] [-size|-B bytes] [-preinit|-P]\n");
894 #else
895 fprintf(stderr, "Usage: nbd-client -name|-N name host [port] nbd_device\n\t[-block-size|-b block size] [-timeout|-t timeout] [-swap|-s]\n\t[-persist|-p] [-nofork|-n] [-systemd-mark|-m]\n\t[-readonly|-R] [-size|-B bytes] [-preinit|-P]\n");
896 #endif
897 fprintf(stderr, "Or : nbd-client -u (with same arguments as above)\n");
898 fprintf(stderr, "Or : nbd-client nbdX\n");
899 fprintf(stderr, "Or : nbd-client -d nbd_device\n");
900 fprintf(stderr, "Or : nbd-client -c nbd_device\n");
901 fprintf(stderr, "Or : nbd-client -h|--help\n");
902 fprintf(stderr, "Or : nbd-client -l|--list host\n");
903 fprintf(stderr, "Or : nbd-client -V|--version\n");
904 #if HAVE_GNUTLS && !defined(NOTLS)
905 fprintf(stderr, "All commands that connect to a host also take:\n\t[-F|-certfile certfile] [-K|-keyfile keyfile]\n\t[-A|-cacertfile cacertfile] [-H|-tlshostname hostname] [-x|-enable-tls]\n\t[-y|-priority gnutls-priority-string]\n");
906 #endif
907 fprintf(stderr, "Default value for blocksize is 512\n");
908 fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */
909 fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n");
910 fprintf(stderr, "blocksizes other than 1024 without patches\n");
911 fprintf(stderr, "Default value for port is 10809. Note that port must always be numeric\n");
912 fprintf(stderr, "Bug reports and general discussion should go to %s\n", PACKAGE_BUGREPORT);
915 void disconnect(char* device) {
916 int nbd = open(device, O_RDWR);
918 if (nbd < 0)
919 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
920 printf("disconnect, ");
921 if (ioctl(nbd, NBD_DISCONNECT)<0)
922 err("Ioctl failed: %m\n");
923 printf("sock, ");
924 if (ioctl(nbd, NBD_CLEAR_SOCK)<0)
925 err("Ioctl failed: %m\n");
926 printf("done\n");
927 close(nbd);
930 static const char *short_opts = "-B:b:c:d:gH:hlnN:PpRSst:uVxy:"
931 #if HAVE_NETLINK
933 #endif
934 #if HAVE_GNUTLS
935 "A:C:F:K:"
936 #endif
939 int main(int argc, char *argv[]) {
940 char* port=NBD_DEFAULT_PORT;
941 int sock, nbd;
942 int blocksize=512;
943 char *hostname=NULL;
944 char *nbddev=NULL;
945 int swap=0;
946 int cont=0;
947 int timeout=0;
948 int G_GNUC_UNUSED nofork=0; // if -dNOFORK
949 pid_t main_pid;
950 u64 size64 = 0;
951 u64 force_size64 = 0;
952 uint16_t flags = 0;
953 bool force_read_only = false;
954 bool preinit = false;
955 int c;
956 int nonspecial=0;
957 int b_unix=0;
958 char* name="";
959 uint16_t needed_flags=0;
960 uint32_t cflags=NBD_FLAG_C_FIXED_NEWSTYLE;
961 uint32_t opts=0;
962 sigset_t block, old;
963 char *certfile = NULL;
964 char *keyfile = NULL;
965 char *cacertfile = NULL;
966 char *tlshostname = NULL;
967 char *priority = NULL;
968 bool tls = false;
969 struct sigaction sa;
970 int num_connections = 1;
971 int netlink = HAVE_NETLINK;
972 int need_disconnect = 0;
973 int *sockfds;
974 struct option long_options[] = {
975 { "cacertfile", required_argument, NULL, 'A' },
976 { "block-size", required_argument, NULL, 'b' },
977 { "size", required_argument, NULL, 'B' },
978 { "check", required_argument, NULL, 'c' },
979 { "connections", required_argument, NULL, 'C'},
980 { "disconnect", required_argument, NULL, 'd' },
981 { "certfile", required_argument, NULL, 'F' },
982 { "no-optgo", no_argument, NULL, 'g' },
983 { "help", no_argument, NULL, 'h' },
984 { "tlshostname", required_argument, NULL, 'H' },
985 { "keyfile", required_argument, NULL, 'K' },
986 { "list", no_argument, NULL, 'l' },
987 #if HAVE_NETLINK
988 { "nonetlink", no_argument, NULL, 'L' },
989 #endif
990 { "systemd-mark", no_argument, NULL, 'm' },
991 { "nofork", no_argument, NULL, 'n' },
992 { "name", required_argument, NULL, 'N' },
993 { "persist", no_argument, NULL, 'p' },
994 { "preinit", no_argument, NULL, 'P' },
995 { "readonly", no_argument, NULL, 'R' },
996 { "swap", no_argument, NULL, 's' },
997 { "timeout", required_argument, NULL, 't' },
998 { "unix", no_argument, NULL, 'u' },
999 { "version", no_argument, NULL, 'V' },
1000 { "enable-tls", no_argument, NULL, 'x' },
1001 { "priority", required_argument, NULL, 'y' },
1002 { 0, 0, 0, 0 },
1004 int i;
1005 bool can_opt_go = true;
1007 logging(MY_NAME);
1009 #if HAVE_GNUTLS && !defined(NOTLS)
1010 tlssession_init();
1011 #endif
1013 while((c=getopt_long_only(argc, argv, short_opts, long_options, NULL))>=0) {
1014 switch(c) {
1015 case 1:
1016 // non-option argument
1017 if(strchr(optarg, '=')) {
1018 // old-style 'bs=' or 'timeout='
1019 // argument
1020 fprintf(stderr, "WARNING: old-style command-line argument encountered. This is deprecated.\n");
1021 if(!strncmp(optarg, "bs=", 3)) {
1022 optarg+=3;
1023 goto blocksize;
1025 if(!strncmp(optarg, "timeout=", 8)) {
1026 optarg+=8;
1027 goto timeout;
1029 usage("unknown option %s encountered", optarg);
1030 exit(EXIT_FAILURE);
1032 switch(nonspecial++) {
1033 case 0:
1034 // host
1035 hostname=optarg;
1036 break;
1037 case 1:
1038 // port
1039 if(!strtol(optarg, NULL, 0)) {
1040 // not parseable as a number, assume it's the device
1041 nbddev = optarg;
1042 nonspecial++;
1043 } else {
1044 port = optarg;
1046 break;
1047 case 2:
1048 // device
1049 nbddev = optarg;
1050 break;
1051 default:
1052 usage("too many non-option arguments specified");
1053 exit(EXIT_FAILURE);
1055 break;
1056 case 'b':
1057 blocksize:
1058 blocksize=(int)strtol(optarg, NULL, 0);
1059 if(blocksize == 0 || (blocksize % 512) != 0) {
1060 fprintf(stderr, "E: blocksize is not a multiple of 512! This is not allowed\n");
1061 exit(EXIT_FAILURE);
1063 break;
1064 case 'B':
1065 force_size64=(u64)strtoull(optarg, NULL, 0);
1066 if(force_size64 == 0) {
1067 fprintf(stderr, "E: Invalid size\n");
1068 exit(EXIT_FAILURE);
1070 break;
1071 case 'c':
1072 return check_conn(optarg, 1);
1073 case 'C':
1074 num_connections = (int)strtol(optarg, NULL, 0);
1075 break;
1076 case 'd':
1077 need_disconnect = 1;
1078 nbddev = strdup(optarg);
1079 break;
1080 case 'g':
1081 can_opt_go = false;
1082 break;
1083 case 'h':
1084 usage(NULL);
1085 exit(EXIT_SUCCESS);
1086 case 'l':
1087 needed_flags |= NBD_FLAG_FIXED_NEWSTYLE;
1088 opts |= NBDC_DO_LIST;
1089 nbddev="";
1090 break;
1091 #if HAVE_NETLINK
1092 case 'L':
1093 netlink = 0;
1094 break;
1095 #endif
1096 case 'm':
1097 argv[0][0] = '@';
1098 break;
1099 case 'n':
1100 nofork=1;
1101 break;
1102 case 'N':
1103 name=optarg;
1104 break;
1105 case 'p':
1106 cont=1;
1107 break;
1108 case 'P':
1109 preinit = true;
1110 break;
1111 case 'R':
1112 force_read_only = true;
1113 break;
1114 case 's':
1115 swap=1;
1116 break;
1117 case 't':
1118 timeout:
1119 timeout=strtol(optarg, NULL, 0);
1120 break;
1121 case 'u':
1122 b_unix = 1;
1123 break;
1124 case 'V':
1125 printf("This is %s, from %s\n", PROG_NAME, PACKAGE_STRING);
1126 return 0;
1127 #if HAVE_GNUTLS && !defined(NOTLS)
1128 case 'x':
1129 tls = true;
1130 break;
1131 case 'F':
1132 certfile=strdup(optarg);
1133 break;
1134 case 'K':
1135 keyfile=strdup(optarg);
1136 break;
1137 case 'A':
1138 cacertfile=strdup(optarg);
1139 break;
1140 case 'H':
1141 tlshostname=strdup(optarg);
1142 break;
1143 case 'y':
1144 priority=strdup(optarg);
1145 break;
1146 #else
1147 case 'F':
1148 case 'K':
1149 case 'H':
1150 case 'A':
1151 case 'y':
1152 fprintf(stderr, "E: TLS support not compiled in\n");
1153 exit(EXIT_FAILURE);
1154 #endif
1155 default:
1156 fprintf(stderr, "E: option eaten by 42 mice\n");
1157 exit(EXIT_FAILURE);
1161 if (need_disconnect) {
1162 if (netlink)
1163 netlink_disconnect(nbddev);
1164 else
1165 disconnect(nbddev);
1166 exit(EXIT_SUCCESS);
1168 #ifdef __ANDROID__
1169 if (swap)
1170 err("swap option unsupported on Android because mlockall is unsupported.");
1171 #endif
1172 if(hostname) {
1173 if((!name || !nbddev) && !(opts & NBDC_DO_LIST)) {
1174 if(!strncmp(hostname, "nbd", 3) || !strncmp(hostname, "/dev/nbd", 8)) {
1175 if(!get_from_config(hostname, &name, &nbddev, &hostname, &blocksize, &timeout, &cont, &swap, &b_unix, &port, &num_connections, &certfile, &keyfile, &cacertfile, &tlshostname, &priority, &can_opt_go)) {
1176 usage("no valid configuration for specified device found", hostname);
1177 exit(EXIT_FAILURE);
1179 } else if (!netlink) {
1180 usage("not enough information specified, and argument didn't look like an nbd device");
1181 exit(EXIT_FAILURE);
1184 } else {
1185 usage("no information specified");
1186 exit(EXIT_FAILURE);
1189 if (keyfile && !certfile)
1190 certfile = strdup(keyfile);
1192 if (certfile != NULL || keyfile != NULL || cacertfile != NULL || tlshostname != NULL) {
1193 tls = true;
1196 if (preinit) {
1197 if (tls) {
1198 fprintf(stderr, "E: preinit connection cannot be used with TLS\n");
1199 exit(EXIT_FAILURE);
1201 if (!force_size64) {
1202 fprintf(stderr, "E: preinit connection requires specifying size\n");
1203 exit(EXIT_FAILURE);
1207 if (!tlshostname && hostname && !b_unix)
1208 tlshostname = strdup(hostname);
1210 if (netlink)
1211 nofork = 1;
1213 if((force_size64 % blocksize) != 0) {
1214 fprintf(stderr, "E: size (%" PRIu64 " bytes) is not a multiple of blocksize (%d)!\n", force_size64, blocksize);
1215 exit(EXIT_FAILURE);
1218 if(strlen(name)==0 && !(opts & NBDC_DO_LIST)) {
1219 printf("Warning: the oldstyle protocol is no longer supported.\nThis method now uses the newstyle protocol with a default export\n");
1222 if(!(opts & NBDC_DO_LIST) && !netlink) {
1223 nbd = open(nbddev, O_RDWR);
1224 if (nbd < 0)
1225 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
1228 if (netlink) {
1229 sockfds = malloc(sizeof(int) * num_connections);
1230 if (!sockfds)
1231 err("Cannot allocate the socket fd's array");
1234 for (i = 0; i < num_connections; i++) {
1235 if (b_unix)
1236 sock = openunix(hostname);
1237 else
1238 sock = opennet(hostname, port);
1239 if (sock < 0)
1240 exit(EXIT_FAILURE);
1242 if (!preinit)
1243 negotiate(&sock, &size64, &flags, name, needed_flags, cflags, opts, certfile, keyfile, cacertfile, tlshostname, tls, priority, can_opt_go);
1244 if (force_read_only)
1245 flags |= NBD_FLAG_READ_ONLY;
1246 if (force_size64)
1247 size64 = force_size64;
1248 if (netlink) {
1249 sockfds[i] = sock;
1250 continue;
1253 if (i == 0) {
1254 setsizes(nbd, size64, blocksize, flags);
1255 set_timeout(nbd, timeout);
1257 finish_sock(sock, nbd, swap);
1258 if (swap) {
1259 if (keyfile)
1260 fprintf(stderr, "Warning: using swap and TLS is prone to deadlock\n");
1261 /* try linux >= 2.6.36 interface first */
1262 if (oom_adjust("/proc/self/oom_score_adj", "-1000")) {
1263 /* fall back to linux <= 2.6.35 interface */
1264 oom_adjust("/proc/self/oom_adj", "-17");
1269 if (netlink) {
1270 int index = -1;
1271 if (nbddev) {
1272 if (sscanf(nbddev, "/dev/nbd%d", &index) != 1)
1273 err("Invalid nbd device target\n");
1275 netlink_configure(index, sockfds, num_connections,
1276 size64, blocksize, flags, timeout);
1277 return 0;
1279 /* Go daemon */
1281 #ifndef NOFORK
1282 if(!nofork) {
1283 if (daemon(0,0) < 0)
1284 err("Cannot detach from terminal");
1287 memset(&sa, 0, sizeof(sa));
1288 sa.sa_handler = SIG_IGN;
1289 sigaction(SIGCHLD, &sa, NULL);
1290 #endif
1291 /* For child to check its parent */
1292 main_pid = getpid();
1293 do {
1294 #ifndef NOFORK
1296 sigfillset(&block);
1297 sigdelset(&block, SIGKILL);
1298 sigdelset(&block, SIGTERM);
1299 sigdelset(&block, SIGPIPE);
1300 sigprocmask(SIG_SETMASK, &block, &old);
1302 if (!fork()) {
1303 /* Due to a race, the kernel NBD driver cannot
1304 * call for a reread of the partition table
1305 * in the handling of the NBD_DO_IT ioctl().
1306 * Therefore, this is done in the first open()
1307 * of the device. We therefore make sure that
1308 * the device is opened at least once after the
1309 * connection was made. This has to be done in a
1310 * separate process, since the NBD_DO_IT ioctl()
1311 * does not return until the NBD device has
1312 * disconnected.
1314 struct timespec req = {
1315 .tv_sec = 0,
1316 .tv_nsec = 100000000,
1318 while(check_conn(nbddev, 0)) {
1319 if (main_pid != getppid()) {
1320 /* check_conn() will not return 0 when nbd disconnected
1321 * and parent exited during this loop. So the child has to
1322 * explicitly check parent identity and exit if parent
1323 * exited */
1324 exit(0);
1326 nanosleep(&req, NULL);
1328 if(open(nbddev, O_RDONLY) < 0) {
1329 perror("could not open device for updating partition table");
1331 exit(0);
1333 #endif
1335 if (ioctl(nbd, NBD_DO_IT) < 0) {
1336 int error = errno;
1337 fprintf(stderr, "nbd,%d: Kernel call returned: %s\n", main_pid, strerror(errno));
1338 if(error==EBADR) {
1339 /* The user probably did 'nbd-client -d' on us.
1340 * quit */
1341 cont=0;
1342 } else {
1343 if(cont) {
1344 u64 new_size;
1345 uint16_t new_flags;
1347 close(sock); close(nbd);
1348 for (;;) {
1349 fprintf(stderr, " Reconnecting\n");
1350 if (b_unix)
1351 sock = openunix(hostname);
1352 else
1353 sock = opennet(hostname, port);
1354 if (sock >= 0)
1355 break;
1356 sleep (1);
1358 nbd = open(nbddev, O_RDWR);
1359 if (nbd < 0)
1360 err("Cannot open NBD: %m");
1361 negotiate(&sock, &new_size, &new_flags, name, needed_flags, cflags, opts, certfile, keyfile, cacertfile, tlshostname, tls, priority, can_opt_go);
1362 if (size64 != new_size) {
1363 err("Size of the device changed. Bye");
1365 setsizes(nbd, size64, blocksize,
1366 new_flags);
1368 set_timeout(nbd, timeout);
1369 finish_sock(sock,nbd,swap);
1372 } else {
1373 /* We're on 2.4. It's not clearly defined what exactly
1374 * happened at this point. Probably best to quit, now
1376 fprintf(stderr, "Kernel call returned.\n");
1377 cont=0;
1379 } while(cont);
1380 printf("sock, ");
1381 ioctl(nbd, NBD_CLEAR_SOCK);
1382 printf("done\n");
1383 return 0;