Refactor the negotiate() and connected functions
[nbd.git] / nbd-client.c
blob06d1440f89cc2faa2295c3da54465ac1d3b8a396
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 if(geteuid() != 0) {
204 err("Failed to setup device. Are you root?\n");
205 } else {
206 err("Failed to setup device, check dmesg\n");
209 return;
210 nla_put_failure:
211 err("Failed to create netlink message\n");
214 static void netlink_disconnect(char *nbddev) {
215 struct nl_sock *socket;
216 struct nl_msg *msg;
217 int driver_id;
219 int index = -1;
220 if (nbddev) {
221 if (sscanf(nbddev, "/dev/nbd%d", &index) != 1)
222 err("Invalid nbd device target\n");
224 if (index < 0)
225 err("Invalid nbd device target\n");
227 socket = get_nbd_socket(&driver_id);
229 msg = nlmsg_alloc();
230 if (!msg)
231 err("Couldn't allocate netlink message\n");
232 genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, driver_id, 0, 0,
233 NBD_CMD_DISCONNECT, 0);
234 NLA_PUT_U32(msg, NBD_ATTR_INDEX, index);
235 if (nl_send_sync(socket, msg) < 0)
236 err("Failed to disconnect device, check dmsg\n");
237 nl_socket_free(socket);
238 return;
239 nla_put_failure:
240 err("Failed to create netlink message\n");
242 #else
243 static void netlink_configure(int index, int *sockfds, int num_connects,
244 u64 size64, int blocksize, uint16_t flags,
245 int timeout)
249 static void netlink_disconnect(char *nbddev)
252 #endif /* HAVE_NETLINK */
254 int check_conn(char* devname, int do_print) {
255 char buf[256];
256 char* p;
257 int fd;
258 int len;
260 if( (p=strrchr(devname, '/')) ) {
261 devname=p+1;
263 if((p=strchr(devname, 'p'))) {
264 /* We can't do checks on partitions. */
265 *p='\0';
267 snprintf(buf, 256, "/sys/block/%s/pid", devname);
268 if((fd=open(buf, O_RDONLY))<0) {
269 if(errno==ENOENT) {
270 return 1;
271 } else {
272 return 2;
275 len=read(fd, buf, 256);
276 if(len < 0) {
277 perror("could not read from server");
278 close(fd);
279 return 2;
281 buf[(len < 256) ? len : 255]='\0';
282 if(do_print) printf("%s\n", buf);
283 close(fd);
284 return 0;
287 int opennet() {
288 int sock;
289 struct addrinfo hints;
290 struct addrinfo *ai = NULL;
291 struct addrinfo *rp = NULL;
292 int e;
294 memset(&hints,'\0',sizeof(hints));
295 hints.ai_family = AF_UNSPEC;
296 hints.ai_socktype = SOCK_STREAM;
297 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
298 hints.ai_protocol = IPPROTO_TCP;
300 e = getaddrinfo(cur_client->hostn, cur_client->port, &hints, &ai);
302 if(e != 0) {
303 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
304 freeaddrinfo(ai);
305 return -1;
308 for(rp = ai; rp != NULL; rp = rp->ai_next) {
309 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
311 if(sock == -1)
312 continue; /* error */
314 if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
315 break; /* success */
317 close(sock);
320 if (rp == NULL) {
321 err_nonfatal("Socket failed: %m");
322 sock = -1;
323 goto err;
326 setmysockopt(sock);
327 err:
328 freeaddrinfo(ai);
329 return sock;
332 int openunix() {
333 int sock;
334 char *path = cur_client->hostn;
335 struct sockaddr_un un_addr;
336 memset(&un_addr, 0, sizeof(un_addr));
338 un_addr.sun_family = AF_UNIX;
339 if (strnlen(path, sizeof(un_addr.sun_path)) == sizeof(un_addr.sun_path)) {
340 err_nonfatal("UNIX socket path too long");
341 return -1;
344 strncpy(un_addr.sun_path, path, sizeof(un_addr.sun_path) - 1);
346 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
347 err_nonfatal("SOCKET failed");
348 return -1;
351 if (connect(sock, (struct sockaddr*)&un_addr, sizeof(un_addr)) == -1) {
352 err_nonfatal("CONNECT failed");
353 close(sock);
354 return -1;
356 return sock;
359 void send_request(int sock, uint32_t opt, ssize_t datasize, void* data) {
360 struct {
361 uint64_t magic;
362 uint32_t opt;
363 uint32_t datasize;
364 } __attribute__((packed)) header = {
365 ntohll(opts_magic),
366 ntohl(opt),
367 ntohl(datasize),
369 if(datasize < 0) {
370 datasize = strlen((char*)data);
371 header.datasize = htonl(datasize);
373 writeit(sock, &header, sizeof(header));
374 if(data != NULL) {
375 writeit(sock, data, datasize);
379 void send_info_request(int sock, uint32_t opt, int n_reqs, uint16_t* reqs, char* name) {
380 uint16_t rlen = htons(n_reqs);
381 uint32_t nlen = htonl(strlen(name));
383 send_request(sock, opt, sizeof(uint32_t) + strlen(name) + sizeof(uint16_t) + n_reqs * sizeof(uint16_t), NULL);
384 writeit(sock, &nlen, sizeof(nlen));
385 writeit(sock, name, strlen(name));
386 writeit(sock, &rlen, sizeof(rlen));
387 if(n_reqs > 0) {
388 writeit(sock, reqs, n_reqs * sizeof(uint16_t));
392 struct reply {
393 uint64_t magic;
394 uint32_t opt;
395 uint32_t reply_type;
396 uint32_t datasize;
397 char data[];
398 } __attribute__((packed));
400 struct reply* read_reply(int sock) {
401 struct reply *retval = malloc(sizeof(struct reply));
403 if (retval == NULL)
404 return NULL;
406 if(readit(sock, retval, sizeof(*retval)) < 0) {
407 free(retval);
408 return NULL;
411 retval->magic = ntohll(retval->magic);
412 retval->opt = ntohl(retval->opt);
413 retval->reply_type = ntohl(retval->reply_type);
414 retval->datasize = ntohl(retval->datasize);
415 if (retval->magic != rep_magic) {
416 fprintf(stderr, "E: received invalid negotiation magic %" PRIu64 " (expected %" PRIu64 ")", retval->magic, rep_magic);
417 exit(EXIT_FAILURE);
419 if (retval->datasize > 0 && retval->datasize < 4096) {
420 struct reply *retval_r = realloc(retval, sizeof(struct reply) + retval->datasize);
421 if (retval_r == NULL) {
422 free(retval);
423 return NULL;
425 retval = retval_r;
426 readit(sock, &(retval->data), retval->datasize);
428 return retval;
431 void ask_list(int sock) {
432 uint32_t opt_server;
433 uint32_t len;
434 uint32_t lenn;
435 uint32_t reptype;
436 uint64_t magic;
437 int rlen;
438 const int BUF_SIZE = 1024;
439 char buf[BUF_SIZE];
441 send_request(sock, NBD_OPT_LIST, 0, NULL);
442 /* newline, move away from the "Negotiation:" line */
443 printf("\n");
444 do {
445 memset(buf, 0, 1024);
446 if(read(sock, &magic, sizeof(magic)) < 0) {
447 err("Reading magic from server: %m");
449 if(read(sock, &opt_server, sizeof(opt_server)) < 0) {
450 err("Reading option: %m");
452 if(read(sock, &reptype, sizeof(reptype)) <0) {
453 err("Reading reply from server: %m");
455 if(read(sock, &len, sizeof(len)) < 0) {
456 err("Reading length from server: %m");
458 magic=ntohll(magic);
459 len=ntohl(len);
460 reptype=ntohl(reptype);
461 if(magic != rep_magic) {
462 err("Not enough magic from server");
464 if(reptype & NBD_REP_FLAG_ERROR) {
465 switch(reptype) {
466 case NBD_REP_ERR_POLICY:
467 fprintf(stderr, "\nE: listing not allowed by server.\n");
468 break;
469 default:
470 fprintf(stderr, "\nE: unexpected error from server.\n");
471 break;
473 if(len > 0 && len < BUF_SIZE) {
474 if((rlen=read(sock, buf, len)) < 0) {
475 fprintf(stderr, "\nE: could not read error message from server\n");
476 } else {
477 buf[rlen] = '\0';
478 fprintf(stderr, "Server said: %s\n", buf);
481 exit(EXIT_FAILURE);
482 } else {
483 if(reptype != NBD_REP_ACK) {
484 if(reptype != NBD_REP_SERVER) {
485 err("Server sent us a reply we don't understand!");
487 if(read(sock, &lenn, sizeof(lenn)) < 0) {
488 fprintf(stderr, "\nE: could not read export name length from server\n");
489 exit(EXIT_FAILURE);
491 lenn=ntohl(lenn);
492 if (lenn >= BUF_SIZE) {
493 fprintf(stderr, "\nE: export name on server too long\n");
494 exit(EXIT_FAILURE);
496 if(read(sock, buf, lenn) < 0) {
497 fprintf(stderr, "\nE: could not read export name from server\n");
498 exit(EXIT_FAILURE);
500 buf[lenn] = 0;
501 printf("%s", buf);
502 len -= lenn;
503 len -= sizeof(lenn);
504 if(len > 0) {
505 if(len >= BUF_SIZE) {
506 fprintf(stderr, "\nE: export description read buffer overflow\n");
507 exit(EXIT_FAILURE);
509 if(read(sock, buf, len) < 0) {
510 fprintf(stderr, "\nE: could not read export description from server\n");
511 exit(EXIT_FAILURE);
513 buf[len] = 0;
514 printf(": %s\n", buf);
515 } else {
516 printf("\n");
520 } while(reptype != NBD_REP_ACK);
521 send_request(sock, NBD_OPT_ABORT, 0, NULL);
524 void parse_sizes(char *buf, uint64_t *size, uint16_t *flags) {
525 memcpy(size, buf, sizeof(*size));
526 *size = ntohll(*size);
527 buf += sizeof(*size);
528 memcpy(flags, buf, sizeof(*flags));
529 *flags = ntohs(*flags);
531 if ((*size>>12) > (uint64_t)~0UL) {
532 printf("size = %luMB", (unsigned long)(*size>>20));
533 err("Exported device is too big for me. Get 64-bit machine :-(\n");
534 } else {
535 printf("size = %luMB", (unsigned long)(*size>>20));
537 printf("\n");
540 void send_opt_exportname(int sock, uint16_t *flags, char* name, uint16_t global_flags) {
541 send_request(sock, NBD_OPT_EXPORT_NAME, -1, name);
542 char b[sizeof(*flags) + sizeof(cur_client->size64)];
543 if(readit(sock, b, sizeof(b)) < 0 && !cur_client->no_optgo) {
544 err("E: server does not support NBD_OPT_GO and dropped connection after sending NBD_OPT_EXPORT_NAME. Try -g.");
546 parse_sizes(b, &(cur_client->size64), flags);
547 if(!(global_flags & NBD_FLAG_NO_ZEROES)) {
548 char buf[125];
549 readit(sock, buf, 124);
553 void negotiate(int *sockp, uint16_t *flags, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts) {
554 u64 magic;
555 uint16_t tmp;
556 uint16_t global_flags;
557 char buf[256] = "\0\0\0\0\0\0\0\0\0";
558 int sock = *sockp;
560 printf("Negotiation: ");
561 readit(sock, buf, 8);
562 if (strcmp(buf, INIT_PASSWD))
563 err("INIT_PASSWD bad");
564 printf(".");
565 readit(sock, &magic, sizeof(magic));
566 magic = ntohll(magic);
567 if (magic != opts_magic) {
568 if(magic == cliserv_magic) {
569 err("It looks like you're trying to connect to an oldstyle server. This is no longer supported since nbd 3.10.");
572 printf(".");
573 readit(sock, &tmp, sizeof(uint16_t));
574 global_flags = ntohs(tmp);
575 if((needed_flags & global_flags) != needed_flags) {
576 /* There's currently really only one reason why this
577 * check could possibly fail, but we may need to change
578 * this error message in the future... */
579 fprintf(stderr, "\nE: Server does not support listing exports\n");
580 exit(EXIT_FAILURE);
583 if (global_flags & NBD_FLAG_NO_ZEROES) {
584 client_flags |= NBD_FLAG_C_NO_ZEROES;
586 client_flags = htonl(client_flags);
587 if (write(sock, &client_flags, sizeof(client_flags)) < 0)
588 err("Failed/2.1: %m");
590 #if HAVE_GNUTLS && !defined(NOTLS)
591 /* TLS */
592 if (cur_client->tls) {
593 int plainfd[2]; // [0] is used by the proxy, [1] is used by NBD
594 tlssession_t *s = NULL;
595 int ret;
596 uint32_t tmp32;
597 uint64_t tmp64;
599 send_request(sock, NBD_OPT_STARTTLS, 0, NULL);
601 if (read(sock, &tmp64, sizeof(tmp64)) < 0)
602 err("Could not read cliserv_magic: %m");
603 tmp64 = ntohll(tmp64);
604 if (tmp64 != NBD_OPT_REPLY_MAGIC) {
605 err("reply magic does not match");
607 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
608 err("Could not read option type: %m");
609 tmp32 = ntohl(tmp32);
610 if (tmp32 != NBD_OPT_STARTTLS)
611 err("Reply to wrong option");
612 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
613 err("Could not read option reply type: %m");
614 tmp32 = ntohl(tmp32);
615 if (tmp32 != NBD_REP_ACK) {
616 err("Option reply type != NBD_REP_ACK");
618 if (read(sock, &tmp32, sizeof(tmp32)) < 0) err(
619 "Could not read option data length: %m");
620 tmp32 = ntohl(tmp32);
621 if (tmp32 != 0) {
622 err("Option reply data length != 0");
624 s = tlssession_new(0,
625 cur_client->key,
626 cur_client->cert,
627 cur_client->cacert,
628 cur_client->tlshostn,
629 cur_client->priority,
630 !(cur_client->cacert) || !(cur_client->tlshostn), // insecure flag
631 #ifdef DODBG
632 1, // debug
633 #else
634 0, // debug
635 #endif
636 NULL, // quitfn
637 NULL, // erroutfn
638 NULL // opaque
640 if (!s)
641 err("Cannot establish TLS session");
643 if (socketpair(AF_UNIX, SOCK_STREAM, 0, plainfd) < 0)
644 err("Cannot get socket pair");
646 if (set_nonblocking(plainfd[0], 0) <0 ||
647 set_nonblocking(plainfd[1], 0) <0 ||
648 set_nonblocking(sock, 0) <0) {
649 close(plainfd[0]);
650 close(plainfd[1]);
651 err("Cannot set socket options");
654 ret = fork();
655 if (ret < 0)
656 err("Could not fork");
657 else if (ret == 0) {
658 // we are the child
659 if (daemon(0, 0) < 0) {
660 /* no one will see this */
661 fprintf(stderr, "Can't detach from the terminal");
662 exit(1);
664 signal (SIGPIPE, SIG_IGN);
665 close(plainfd[1]);
666 tlssession_mainloop(sock, plainfd[0], s);
667 close(sock);
668 close(plainfd[0]);
669 exit(0);
671 close(plainfd[0]);
672 close(sock);
673 sock = plainfd[1]; /* use the decrypted FD from now on */
674 *sockp = sock;
676 #else
677 if (cur_client->tls) {
678 err("TLS requested but support not compiled in");
680 #endif
682 if(do_opts & NBDC_DO_LIST) {
683 ask_list(sock);
684 exit(EXIT_SUCCESS);
687 struct reply *rep = NULL;
689 if(cur_client->no_optgo) {
690 send_opt_exportname(sock, flags, cur_client->name, global_flags);
691 return;
694 send_info_request(sock, NBD_OPT_GO, 0, NULL, cur_client->name);
696 do {
697 if(rep != NULL) free(rep);
698 rep = read_reply(sock);
699 if(rep == NULL) {
700 err("Unable to read reply.");
701 exit(EXIT_FAILURE);
703 if(rep->reply_type & NBD_REP_FLAG_ERROR) {
704 switch(rep->reply_type) {
705 case NBD_REP_ERR_UNSUP:
706 /* server doesn't support NBD_OPT_GO or NBD_OPT_INFO,
707 * fall back to NBD_OPT_EXPORT_NAME */
708 send_opt_exportname(sock, flags, cur_client->name, global_flags);
709 free(rep);
710 return;
711 case NBD_REP_ERR_POLICY:
712 if(rep->datasize > 0) {
713 char errstr[1024];
714 rep->data[rep->datasize - 1] = '\0';
715 snprintf(errstr, sizeof errstr, "Connection not allowed by server policy. Server said: %s", rep->data);
716 err(errstr);
717 } else {
718 err("Connection not allowed by server policy.");
720 free(rep);
721 exit(EXIT_FAILURE);
722 default:
723 if(rep->datasize > 0) {
724 char errstr[1024];
725 rep->data[rep->datasize - 1] = '\0';
726 snprintf(errstr, sizeof errstr, "Unknown error returned by server. Server said: %s", rep->data);
727 err(errstr);
728 } else {
729 err("Unknown error returned by server.");
731 free(rep);
732 exit(EXIT_FAILURE);
735 uint16_t info_type;
736 switch(rep->reply_type) {
737 case NBD_REP_INFO:
738 memcpy(&info_type, rep->data, 2);
739 info_type = htons(info_type);
740 switch(info_type) {
741 case NBD_INFO_EXPORT:
742 parse_sizes(rep->data + 2, &(cur_client->size64), flags);
743 break;
744 default:
745 // ignore these, don't need them
746 break;
748 break;
749 case NBD_REP_ACK:
750 break;
751 default:
752 err_nonfatal("Unknown reply to NBD_OPT_GO received, ignoring");
754 } while(rep->reply_type != NBD_REP_ACK);
755 free(rep);
758 bool get_from_config() {
759 bool retval = false;
760 yyin = fopen(SYSCONFDIR "/nbdtab", "r");
761 yyout = fopen("/dev/null", "w");
763 if(!strncmp(cur_client->dev, "/dev/", 5)) {
764 cur_client->dev += 5;
766 if(yyin == NULL) {
767 fprintf(stderr, "while opening %s: ", SYSCONFDIR "/nbdtab");
768 perror("could not open config file");
769 goto out;
771 yyparse();
773 if(!found_config || parse_error) {
774 goto out;
777 retval = true;
778 out:
779 if(yyin != NULL) {
780 fclose(yyin);
782 if(yyout != NULL) {
783 fclose(yyout);
785 return retval;
788 void setsizes(int nbd, u64 size64, int blocksize, u32 flags) {
789 unsigned long size;
790 int read_only = (flags & NBD_FLAG_READ_ONLY) ? 1 : 0;
792 if (size64>>12 > (uint64_t)~0UL)
793 err("Device too large.\n");
794 else {
795 int tmp_blocksize = 4096;
796 if (size64 / (u64)blocksize <= (uint64_t)~0UL)
797 tmp_blocksize = blocksize;
798 if (ioctl(nbd, NBD_SET_BLKSIZE, tmp_blocksize) < 0) {
799 fprintf(stderr, "Failed to set blocksize %d\n",
800 tmp_blocksize);
801 err("Ioctl/1.1a failed: %m\n");
803 size = (unsigned long)(size64 / (u64)tmp_blocksize);
804 if (ioctl(nbd, NBD_SET_SIZE_BLOCKS, size) < 0)
805 err("Ioctl/1.1b failed: %m\n");
806 if (tmp_blocksize != blocksize) {
807 if (ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long)blocksize) < 0) {
808 fprintf(stderr, "Failed to set blocksize %d\n",
809 blocksize);
810 err("Ioctl/1.1c failed: %m\n");
813 fprintf(stderr, "bs=%d, sz=%" PRIu64 " bytes\n", blocksize, (u64)tmp_blocksize * size);
816 ioctl(nbd, NBD_CLEAR_SOCK);
818 /* ignore error as kernel may not support */
819 ioctl(nbd, NBD_SET_FLAGS, (unsigned long) flags);
821 if (ioctl(nbd, BLKROSET, (unsigned long) &read_only) < 0)
822 err("Unable to set read-only attribute for device");
825 void set_timeout(int nbd, int timeout) {
826 if (timeout) {
827 if (ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long)timeout) < 0)
828 err("Ioctl NBD_SET_TIMEOUT failed: %m\n");
829 fprintf(stderr, "timeout=%d\n", timeout);
833 void finish_sock(int sock, int nbd, int swap) {
834 if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) {
835 if (errno == EBUSY)
836 err("Kernel doesn't support multiple connections\n");
837 else
838 err("Ioctl NBD_SET_SOCK failed: %m\n");
841 #ifndef __ANDROID__
842 if (swap)
843 mlockall(MCL_CURRENT | MCL_FUTURE);
844 #endif
847 static int
848 oom_adjust(const char *file, const char *value)
850 int fd, rc;
851 size_t len;
853 fd = open(file, O_WRONLY);
854 if (fd < 0)
855 return -1;
856 len = strlen(value);
857 rc = write(fd, value, len) != (ssize_t) len;
858 close(fd);
859 return rc ? -1 : 0;
862 void usage(char* errmsg, ...) {
863 if(errmsg) {
864 char tmp[256];
865 va_list ap;
866 va_start(ap, errmsg);
867 snprintf(tmp, 256, "ERROR: %s\n\n", errmsg);
868 vfprintf(stderr, tmp, ap);
869 va_end(ap);
870 } else {
871 fprintf(stderr, "%s version %s\n", PROG_NAME, PACKAGE_VERSION);
873 #if HAVE_NETLINK
874 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");
875 #else
876 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");
877 #endif
878 fprintf(stderr, "Or : nbd-client -u (with same arguments as above)\n");
879 fprintf(stderr, "Or : nbd-client nbdX\n");
880 fprintf(stderr, "Or : nbd-client -d nbd_device\n");
881 fprintf(stderr, "Or : nbd-client -c nbd_device\n");
882 fprintf(stderr, "Or : nbd-client -h|--help\n");
883 fprintf(stderr, "Or : nbd-client -l|--list host\n");
884 fprintf(stderr, "Or : nbd-client -V|--version\n");
885 #if HAVE_GNUTLS && !defined(NOTLS)
886 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");
887 #endif
888 fprintf(stderr, "Default value for blocksize is 512\n");
889 fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */
890 fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n");
891 fprintf(stderr, "blocksizes other than 1024 without patches\n");
892 fprintf(stderr, "Default value for port is 10809. Note that port must always be numeric\n");
893 fprintf(stderr, "Bug reports and general discussion should go to %s\n", PACKAGE_BUGREPORT);
896 void disconnect(char* device) {
897 int nbd = open(device, O_RDWR);
899 if (nbd < 0)
900 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
901 printf("disconnect, ");
902 if (ioctl(nbd, NBD_DISCONNECT)<0)
903 err("Ioctl failed: %m\n");
904 printf("sock, ");
905 if (ioctl(nbd, NBD_CLEAR_SOCK)<0)
906 err("Ioctl failed: %m\n");
907 printf("done\n");
908 close(nbd);
911 static const char *short_opts = "-B:b:c:d:gH:hlnN:PpRSst:uVxy:"
912 #if HAVE_NETLINK
914 #endif
915 #if HAVE_GNUTLS
916 "A:C:F:K:"
917 #endif
920 int main(int argc, char *argv[]) {
921 char* port=NBD_DEFAULT_PORT;
922 int sock, nbd;
923 int cont=0;
924 int G_GNUC_UNUSED nofork=0; // if -dNOFORK
925 pid_t main_pid;
926 uint16_t flags = 0;
927 int c;
928 int nonspecial=0;
929 uint16_t needed_flags=0;
930 uint32_t cflags=NBD_FLAG_C_FIXED_NEWSTYLE;
931 uint32_t opts=0;
932 sigset_t block, old;
933 struct sigaction sa;
934 int netlink = HAVE_NETLINK;
935 int need_disconnect = 0;
936 int *sockfds;
937 struct option long_options[] = {
938 { "cacertfile", required_argument, NULL, 'A' },
939 { "block-size", required_argument, NULL, 'b' },
940 { "size", required_argument, NULL, 'B' },
941 { "check", required_argument, NULL, 'c' },
942 { "connections", required_argument, NULL, 'C'},
943 { "disconnect", required_argument, NULL, 'd' },
944 { "certfile", required_argument, NULL, 'F' },
945 { "no-optgo", no_argument, NULL, 'g' },
946 { "help", no_argument, NULL, 'h' },
947 { "tlshostname", required_argument, NULL, 'H' },
948 { "keyfile", required_argument, NULL, 'K' },
949 { "list", no_argument, NULL, 'l' },
950 #if HAVE_NETLINK
951 { "nonetlink", no_argument, NULL, 'L' },
952 #endif
953 { "systemd-mark", no_argument, NULL, 'm' },
954 { "nofork", no_argument, NULL, 'n' },
955 { "name", required_argument, NULL, 'N' },
956 { "persist", no_argument, NULL, 'p' },
957 { "preinit", no_argument, NULL, 'P' },
958 { "readonly", no_argument, NULL, 'R' },
959 { "swap", no_argument, NULL, 's' },
960 { "timeout", required_argument, NULL, 't' },
961 { "unix", no_argument, NULL, 'u' },
962 { "version", no_argument, NULL, 'V' },
963 { "enable-tls", no_argument, NULL, 'x' },
964 { "priority", required_argument, NULL, 'y' },
965 { 0, 0, 0, 0 },
967 int i;
969 logging(MY_NAME);
971 #if HAVE_GNUTLS && !defined(NOTLS)
972 tlssession_init();
973 #endif
974 cur_client = calloc(sizeof(CLIENT), 1);
975 cur_client->bs = 512;
976 cur_client->nconn = 1;
977 cur_client->port = NBD_DEFAULT_PORT;
979 while((c=getopt_long_only(argc, argv, short_opts, long_options, NULL))>=0) {
980 switch(c) {
981 case 1:
982 // non-option argument
983 if(strchr(optarg, '=')) {
984 // old-style 'bs=' or 'timeout='
985 // argument
986 fprintf(stderr, "WARNING: old-style command-line argument encountered. This is deprecated.\n");
987 if(!strncmp(optarg, "bs=", 3)) {
988 optarg+=3;
989 goto blocksize;
991 if(!strncmp(optarg, "timeout=", 8)) {
992 optarg+=8;
993 goto timeout;
995 usage("unknown option %s encountered", optarg);
996 exit(EXIT_FAILURE);
998 switch(nonspecial++) {
999 case 0:
1000 // host
1001 cur_client->hostn=optarg;
1002 break;
1003 case 1:
1004 // port
1005 if(!strtol(optarg, NULL, 0)) {
1006 // not parseable as a number, assume it's the device
1007 cur_client->dev = optarg;
1008 nonspecial++;
1009 } else {
1010 port = optarg;
1012 break;
1013 case 2:
1014 // device
1015 cur_client->dev = optarg;
1016 break;
1017 default:
1018 usage("too many non-option arguments specified");
1019 exit(EXIT_FAILURE);
1021 break;
1022 case 'b':
1023 blocksize:
1024 cur_client->bs=(int)strtol(optarg, NULL, 0);
1025 if(cur_client->bs == 0 || (cur_client->bs % 512) != 0) {
1026 fprintf(stderr, "E: blocksize is not a multiple of 512! This is not allowed\n");
1027 exit(EXIT_FAILURE);
1029 break;
1030 case 'B':
1031 cur_client->force_size64=(uint64_t)strtoull(optarg, NULL, 0);
1032 if(cur_client->force_size64 == 0) {
1033 fprintf(stderr, "E: Invalid size\n");
1034 exit(EXIT_FAILURE);
1036 break;
1037 case 'c':
1038 return check_conn(optarg, 1);
1039 case 'C':
1040 cur_client->nconn = (int)strtol(optarg, NULL, 0);
1041 break;
1042 case 'd':
1043 need_disconnect = 1;
1044 cur_client->dev = strdup(optarg);
1045 break;
1046 case 'g':
1047 cur_client->no_optgo = true;
1048 break;
1049 case 'h':
1050 usage(NULL);
1051 exit(EXIT_SUCCESS);
1052 case 'l':
1053 needed_flags |= NBD_FLAG_FIXED_NEWSTYLE;
1054 opts |= NBDC_DO_LIST;
1055 cur_client->dev="";
1056 break;
1057 #if HAVE_NETLINK
1058 case 'L':
1059 netlink = 0;
1060 break;
1061 #endif
1062 case 'm':
1063 argv[0][0] = '@';
1064 break;
1065 case 'n':
1066 nofork=1;
1067 break;
1068 case 'N':
1069 cur_client->name = optarg;
1070 break;
1071 case 'p':
1072 cont=1;
1073 break;
1074 case 'P':
1075 cur_client->preinit = true;
1076 break;
1077 case 'R':
1078 cur_client->force_ro = true;
1079 break;
1080 case 's':
1081 cur_client->swap = true;
1082 break;
1083 case 't':
1084 timeout:
1085 cur_client->timeout = strtol(optarg, NULL, 0);
1086 break;
1087 case 'u':
1088 cur_client->b_unix = 1;
1089 break;
1090 case 'V':
1091 printf("This is %s, from %s\n", PROG_NAME, PACKAGE_STRING);
1092 return 0;
1093 #if HAVE_GNUTLS && !defined(NOTLS)
1094 case 'x':
1095 cur_client->tls = true;
1096 break;
1097 case 'F':
1098 cur_client->cert=strdup(optarg);
1099 break;
1100 case 'K':
1101 cur_client->key=strdup(optarg);
1102 break;
1103 case 'A':
1104 cur_client->cacert=strdup(optarg);
1105 break;
1106 case 'H':
1107 cur_client->tlshostn=strdup(optarg);
1108 break;
1109 case 'y':
1110 cur_client->priority=strdup(optarg);
1111 break;
1112 #else
1113 case 'F':
1114 case 'K':
1115 case 'H':
1116 case 'A':
1117 case 'y':
1118 fprintf(stderr, "E: TLS support not compiled in\n");
1119 exit(EXIT_FAILURE);
1120 #endif
1121 default:
1122 fprintf(stderr, "E: option eaten by 42 mice\n");
1123 exit(EXIT_FAILURE);
1127 if (need_disconnect) {
1128 if (netlink)
1129 netlink_disconnect(cur_client->dev);
1130 else
1131 disconnect(cur_client->dev);
1132 exit(EXIT_SUCCESS);
1134 #ifdef __ANDROID__
1135 if (swap)
1136 err("swap option unsupported on Android because mlockall is unsupported.");
1137 #endif
1138 if(cur_client->hostn) {
1139 if((!cur_client->name || !cur_client->dev) && !(opts & NBDC_DO_LIST)) {
1140 if(!strncmp(cur_client->hostn, "nbd", 3) || !strncmp(cur_client->hostn, "/dev/nbd", 8)) {
1141 cur_client->dev = cur_client->hostn;
1142 if(!get_from_config()) {
1143 usage("no valid configuration for specified device found", cur_client->hostn);
1144 exit(EXIT_FAILURE);
1146 } else if (!netlink) {
1147 usage("not enough information specified, and argument didn't look like an nbd device");
1148 exit(EXIT_FAILURE);
1151 } else {
1152 usage("no information specified");
1153 exit(EXIT_FAILURE);
1156 if (cur_client->key && !cur_client->cert)
1157 cur_client->cert = strdup(cur_client->key);
1159 if (cur_client->cert != NULL || cur_client->key != NULL || cur_client->cacert != NULL || cur_client->tlshostn != NULL) {
1160 cur_client->tls = true;
1163 if (cur_client->preinit) {
1164 if (cur_client->tls) {
1165 fprintf(stderr, "E: preinit connection cannot be used with TLS\n");
1166 exit(EXIT_FAILURE);
1168 if (!cur_client->force_size64) {
1169 fprintf(stderr, "E: preinit connection requires specifying size\n");
1170 exit(EXIT_FAILURE);
1174 if (!cur_client->tlshostn && cur_client->hostn && !cur_client->b_unix)
1175 cur_client->tlshostn = strdup(cur_client->hostn);
1177 if (netlink)
1178 nofork = 1;
1180 if((cur_client->force_size64 % cur_client->bs) != 0) {
1181 fprintf(stderr, "E: size (%" PRIu64 " bytes) is not a multiple of blocksize (%d)!\n", cur_client->force_size64, cur_client->bs);
1182 exit(EXIT_FAILURE);
1185 if((!cur_client->name || strlen(cur_client->name)==0) && !(opts & NBDC_DO_LIST)) {
1186 printf("Warning: the oldstyle protocol is no longer supported.\nThis method now uses the newstyle protocol with a default export\n");
1189 if(!(opts & NBDC_DO_LIST) && !netlink) {
1190 nbd = open(cur_client->dev, O_RDWR);
1191 if (nbd < 0)
1192 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
1195 if (netlink) {
1196 sockfds = malloc(sizeof(int) * cur_client->nconn);
1197 if (!sockfds)
1198 err("Cannot allocate the socket fd's array");
1201 for (i = 0; i < cur_client->nconn; i++) {
1202 if (cur_client->b_unix)
1203 sock = openunix(cur_client->hostn);
1204 else
1205 sock = opennet(cur_client->hostn, cur_client->port);
1206 if (sock < 0)
1207 exit(EXIT_FAILURE);
1209 if (!cur_client->preinit)
1210 negotiate(&sock, &flags, needed_flags, cflags, opts);
1211 if (cur_client->force_ro)
1212 flags |= NBD_FLAG_READ_ONLY;
1213 if (cur_client->force_size64)
1214 cur_client->size64 = cur_client->force_size64;
1215 if (netlink) {
1216 sockfds[i] = sock;
1217 continue;
1220 if (i == 0) {
1221 setsizes(nbd, cur_client->size64, cur_client->bs, flags);
1222 set_timeout(nbd, cur_client->timeout);
1224 finish_sock(sock, nbd, cur_client->swap);
1225 if (cur_client->swap) {
1226 if (cur_client->tls)
1227 fprintf(stderr, "Warning: using swap and TLS is prone to deadlock\n");
1228 /* try linux >= 2.6.36 interface first */
1229 if (oom_adjust("/proc/self/oom_score_adj", "-1000")) {
1230 /* fall back to linux <= 2.6.35 interface */
1231 oom_adjust("/proc/self/oom_adj", "-17");
1236 if (netlink) {
1237 int index = -1;
1238 if (cur_client->dev) {
1239 if (sscanf(cur_client->dev, "/dev/nbd%d", &index) != 1)
1240 err("Invalid nbd device target\n");
1242 netlink_configure(index, sockfds, cur_client->nconn,
1243 cur_client->size64, cur_client->bs, flags, cur_client->timeout);
1244 return 0;
1246 /* Go daemon */
1248 #ifndef NOFORK
1249 if(!nofork) {
1250 if (daemon(0,0) < 0)
1251 err("Cannot detach from terminal");
1254 memset(&sa, 0, sizeof(sa));
1255 sa.sa_handler = SIG_IGN;
1256 sigaction(SIGCHLD, &sa, NULL);
1257 #endif
1258 /* For child to check its parent */
1259 main_pid = getpid();
1260 do {
1261 #ifndef NOFORK
1263 sigfillset(&block);
1264 sigdelset(&block, SIGKILL);
1265 sigdelset(&block, SIGTERM);
1266 sigdelset(&block, SIGPIPE);
1267 sigprocmask(SIG_SETMASK, &block, &old);
1269 if (!fork()) {
1270 /* Due to a race, the kernel NBD driver cannot
1271 * call for a reread of the partition table
1272 * in the handling of the NBD_DO_IT ioctl().
1273 * Therefore, this is done in the first open()
1274 * of the device. We therefore make sure that
1275 * the device is opened at least once after the
1276 * connection was made. This has to be done in a
1277 * separate process, since the NBD_DO_IT ioctl()
1278 * does not return until the NBD device has
1279 * disconnected.
1281 struct timespec req = {
1282 .tv_sec = 0,
1283 .tv_nsec = 100000000,
1285 while(check_conn(cur_client->dev, 0)) {
1286 if (main_pid != getppid()) {
1287 /* check_conn() will not return 0 when nbd disconnected
1288 * and parent exited during this loop. So the child has to
1289 * explicitly check parent identity and exit if parent
1290 * exited */
1291 exit(0);
1293 nanosleep(&req, NULL);
1295 if(open(cur_client->dev, O_RDONLY) < 0) {
1296 perror("could not open device for updating partition table");
1298 exit(0);
1300 #endif
1302 if (ioctl(nbd, NBD_DO_IT) < 0) {
1303 int error = errno;
1304 fprintf(stderr, "nbd,%d: Kernel call returned: %s\n", main_pid, strerror(errno));
1305 if(error==EBADR) {
1306 /* The user probably did 'nbd-client -d' on us.
1307 * quit */
1308 cont=0;
1309 } else {
1310 if(cont) {
1311 uint64_t old_size = cur_client->size64;
1312 uint16_t new_flags;
1314 close(sock); close(nbd);
1315 for (;;) {
1316 fprintf(stderr, " Reconnecting\n");
1317 if (cur_client->b_unix)
1318 sock = openunix();
1319 else
1320 sock = opennet();
1321 if (sock >= 0)
1322 break;
1323 sleep (1);
1325 nbd = open(cur_client->dev, O_RDWR);
1326 if (nbd < 0)
1327 err("Cannot open NBD: %m");
1328 negotiate(&sock, &new_flags, needed_flags, cflags, opts);
1329 if (old_size != cur_client->size64) {
1330 err("Size of the device changed. Bye");
1332 setsizes(nbd, cur_client->size64, cur_client->bs,
1333 new_flags);
1335 set_timeout(nbd, cur_client->timeout);
1336 finish_sock(sock,nbd,cur_client->swap);
1339 } else {
1340 /* We're on 2.4. It's not clearly defined what exactly
1341 * happened at this point. Probably best to quit, now
1343 fprintf(stderr, "Kernel call returned.\n");
1344 cont=0;
1346 } while(cont);
1347 printf("sock, ");
1348 ioctl(nbd, NBD_CLEAR_SOCK);
1349 printf("done\n");
1350 return 0;