Ensure this is available, too
[nbd.git] / nbd-client.c
blob0830c61d810b4ad88350a35607c7f5639c1d97cc
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 #ifdef WITH_SDP
64 #include <sdp_inet.h>
65 #endif
67 #define NBDC_DO_LIST 1
69 #if HAVE_NETLINK
70 static int callback(struct nl_msg *msg, void *arg) {
71 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
72 struct nlattr *msg_attr[NBD_ATTR_MAX + 1];
73 int ret;
74 uint32_t index;
76 ret = nla_parse(msg_attr, NBD_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
77 genlmsg_attrlen(gnlh, 0), NULL);
78 if (ret)
79 err("Invalid response from the kernel\n");
80 if (!msg_attr[NBD_ATTR_INDEX])
81 err("Did not receive index from the kernel\n");
82 index = nla_get_u32(msg_attr[NBD_ATTR_INDEX]);
83 printf("Connected /dev/nbd%d\n", (int)index);
84 return NL_OK;
87 static struct nl_sock *get_nbd_socket(int *driver_id) {
88 struct nl_sock *socket;
90 socket = nl_socket_alloc();
91 if (!socket)
92 err("Couldn't allocate netlink socket\n");
94 if (genl_connect(socket))
95 err("Couldn't connect to the generic netlink socket\n");
96 *driver_id = genl_ctrl_resolve(socket, "nbd");
97 if (*driver_id < 0)
98 err("Couldn't resolve the nbd netlink family, make sure the nbd module is loaded and your nbd driver supports the netlink interface.\n");
99 return socket;
102 static void netlink_configure(int index, int *sockfds, int num_connects,
103 u64 size64, int blocksize, uint16_t flags,
104 int timeout) {
105 struct nl_sock *socket;
106 struct nlattr *sock_attr;
107 struct nl_msg *msg;
108 int driver_id, i;
110 socket = get_nbd_socket(&driver_id);
111 nl_socket_modify_cb(socket, NL_CB_VALID, NL_CB_CUSTOM, callback, NULL);
113 msg = nlmsg_alloc();
114 if (!msg)
115 err("Couldn't allocate netlink message\n");
116 genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, driver_id, 0, 0,
117 NBD_CMD_CONNECT, 0);
118 if (index >= 0)
119 NLA_PUT_U32(msg, NBD_ATTR_INDEX, index);
120 NLA_PUT_U64(msg, NBD_ATTR_SIZE_BYTES, size64);
121 NLA_PUT_U64(msg, NBD_ATTR_BLOCK_SIZE_BYTES, blocksize);
122 NLA_PUT_U64(msg, NBD_ATTR_SERVER_FLAGS, flags);
123 if (timeout)
124 NLA_PUT_U64(msg, NBD_ATTR_TIMEOUT, timeout);
126 sock_attr = nla_nest_start(msg, NBD_ATTR_SOCKETS);
127 if (!sock_attr)
128 err("Couldn't nest the sockets for our connection\n");
129 for (i = 0; i < num_connects; i++) {
130 struct nlattr *sock_opt;
131 sock_opt = nla_nest_start(msg, NBD_SOCK_ITEM);
132 if (!sock_opt)
133 err("Couldn't nest the sockets for our connection\n");
134 NLA_PUT_U32(msg, NBD_SOCK_FD, sockfds[i]);
135 nla_nest_end(msg, sock_opt);
137 nla_nest_end(msg, sock_attr);
139 if (nl_send_sync(socket, msg) < 0)
140 err("Failed to setup device, check dmesg\n");
141 return;
142 nla_put_failure:
143 err("Failed to create netlink message\n");
146 static void netlink_disconnect(char *nbddev) {
147 struct nl_sock *socket;
148 struct nl_msg *msg;
149 int driver_id;
151 int index = -1;
152 if (nbddev) {
153 if (sscanf(nbddev, "/dev/nbd%d", &index) != 1)
154 err("Invalid nbd device target\n");
156 if (index < 0)
157 err("Invalid nbd device target\n");
159 socket = get_nbd_socket(&driver_id);
161 msg = nlmsg_alloc();
162 if (!msg)
163 err("Couldn't allocate netlink message\n");
164 genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, driver_id, 0, 0,
165 NBD_CMD_DISCONNECT, 0);
166 NLA_PUT_U32(msg, NBD_ATTR_INDEX, index);
167 if (nl_send_sync(socket, msg) < 0)
168 err("Failed to disconnect device, check dmsg\n");
169 nl_socket_free(socket);
170 return;
171 nla_put_failure:
172 err("Failed to create netlink message\n");
174 #else
175 static void netlink_configure(int index, int *sockfds, int num_connects,
176 u64 size64, int blocksize, uint16_t flags,
177 int timeout)
181 static void netlink_disconnect(char *nbddev)
184 #endif /* HAVE_NETLINK */
186 int check_conn(char* devname, int do_print) {
187 char buf[256];
188 char* p;
189 int fd;
190 int len;
192 if( (p=strrchr(devname, '/')) ) {
193 devname=p+1;
195 if((p=strchr(devname, 'p'))) {
196 /* We can't do checks on partitions. */
197 *p='\0';
199 snprintf(buf, 256, "/sys/block/%s/pid", devname);
200 if((fd=open(buf, O_RDONLY))<0) {
201 if(errno==ENOENT) {
202 return 1;
203 } else {
204 return 2;
207 len=read(fd, buf, 256);
208 if(len < 0) {
209 perror("could not read from server");
210 close(fd);
211 return 2;
213 buf[(len < 256) ? len : 255]='\0';
214 if(do_print) printf("%s\n", buf);
215 close(fd);
216 return 0;
219 int opennet(char *name, char* portstr, int sdp) {
220 int sock;
221 struct addrinfo hints;
222 struct addrinfo *ai = NULL;
223 struct addrinfo *rp = NULL;
224 int e;
226 memset(&hints,'\0',sizeof(hints));
227 hints.ai_family = AF_UNSPEC;
228 hints.ai_socktype = SOCK_STREAM;
229 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
230 hints.ai_protocol = IPPROTO_TCP;
232 e = getaddrinfo(name, portstr, &hints, &ai);
234 if(e != 0) {
235 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
236 freeaddrinfo(ai);
237 return -1;
240 if(sdp) {
241 #ifdef WITH_SDP
242 if (ai->ai_family == AF_INET)
243 ai->ai_family = AF_INET_SDP;
244 else (ai->ai_family == AF_INET6)
245 ai->ai_family = AF_INET6_SDP;
246 #else
247 err("Can't do SDP: I was not compiled with SDP support!");
248 #endif
251 for(rp = ai; rp != NULL; rp = rp->ai_next) {
252 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
254 if(sock == -1)
255 continue; /* error */
257 if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
258 break; /* success */
260 close(sock);
263 if (rp == NULL) {
264 err_nonfatal("Socket failed: %m");
265 sock = -1;
266 goto err;
269 setmysockopt(sock);
270 err:
271 freeaddrinfo(ai);
272 return sock;
275 int openunix(const char *path) {
276 int sock;
277 struct sockaddr_un un_addr;
278 memset(&un_addr, 0, sizeof(un_addr));
280 un_addr.sun_family = AF_UNIX;
281 if (strnlen(path, sizeof(un_addr.sun_path)) == sizeof(un_addr.sun_path)) {
282 err_nonfatal("UNIX socket path too long");
283 return -1;
286 strncpy(un_addr.sun_path, path, sizeof(un_addr.sun_path) - 1);
288 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
289 err_nonfatal("SOCKET failed");
290 return -1;
293 if (connect(sock, &un_addr, sizeof(un_addr)) == -1) {
294 err_nonfatal("CONNECT failed");
295 close(sock);
296 return -1;
298 return sock;
301 void send_request(int sock, uint32_t opt, ssize_t datasize, void* data) {
302 struct {
303 uint64_t magic;
304 uint32_t opt;
305 uint32_t datasize;
306 } __attribute__((packed)) header = {
307 ntohll(opts_magic),
308 ntohl(opt),
309 ntohl(datasize),
311 if(datasize < 0) {
312 datasize = strlen((char*)data);
313 header.datasize = htonl(datasize);
315 writeit(sock, &header, sizeof(header));
316 if(data != NULL) {
317 writeit(sock, data, datasize);
321 void send_info_request(int sock, uint32_t opt, int n_reqs, uint16_t* reqs, char* name) {
322 uint16_t rlen = htons(n_reqs);
323 uint32_t nlen = htonl(strlen(name));
325 send_request(sock, opt, sizeof(uint32_t) + strlen(name) + sizeof(uint16_t) + n_reqs * sizeof(uint16_t), NULL);
326 writeit(sock, &nlen, sizeof(nlen));
327 writeit(sock, name, strlen(name));
328 writeit(sock, &rlen, sizeof(rlen));
329 if(n_reqs > 0) {
330 writeit(sock, reqs, n_reqs * sizeof(uint16_t));
334 struct reply {
335 uint64_t magic;
336 uint32_t opt;
337 uint32_t reply_type;
338 uint32_t datasize;
339 char data[];
340 } __attribute__((packed));
342 struct reply* read_reply(int sock) {
343 struct reply *retval = malloc(sizeof(struct reply));
344 readit(sock, retval, sizeof(*retval));
345 retval->magic = ntohll(retval->magic);
346 retval->opt = ntohl(retval->opt);
347 retval->reply_type = ntohl(retval->reply_type);
348 retval->datasize = ntohl(retval->datasize);
349 if (retval->magic != rep_magic) {
350 fprintf(stderr, "E: received invalid negotiation magic %" PRIu64 " (expected %" PRIu64 ")", retval->magic, rep_magic);
351 exit(EXIT_FAILURE);
353 if (retval->datasize > 0) {
354 retval = realloc(retval, sizeof(struct reply) + retval->datasize);
355 readit(sock, &(retval->data), retval->datasize);
357 return retval;
360 void ask_list(int sock) {
361 uint32_t opt_server;
362 uint32_t len;
363 uint32_t lenn;
364 uint32_t reptype;
365 uint64_t magic;
366 int rlen;
367 const int BUF_SIZE = 1024;
368 char buf[BUF_SIZE];
370 send_request(sock, NBD_OPT_LIST, 0, NULL);
371 /* newline, move away from the "Negotiation:" line */
372 printf("\n");
373 do {
374 memset(buf, 0, 1024);
375 if(read(sock, &magic, sizeof(magic)) < 0) {
376 err("Reading magic from server: %m");
378 if(read(sock, &opt_server, sizeof(opt_server)) < 0) {
379 err("Reading option: %m");
381 if(read(sock, &reptype, sizeof(reptype)) <0) {
382 err("Reading reply from server: %m");
384 if(read(sock, &len, sizeof(len)) < 0) {
385 err("Reading length from server: %m");
387 magic=ntohll(magic);
388 len=ntohl(len);
389 reptype=ntohl(reptype);
390 if(magic != rep_magic) {
391 err("Not enough magic from server");
393 if(reptype & NBD_REP_FLAG_ERROR) {
394 switch(reptype) {
395 case NBD_REP_ERR_POLICY:
396 fprintf(stderr, "\nE: listing not allowed by server.\n");
397 break;
398 default:
399 fprintf(stderr, "\nE: unexpected error from server.\n");
400 break;
402 if(len > 0 && len < BUF_SIZE) {
403 if((rlen=read(sock, buf, len)) < 0) {
404 fprintf(stderr, "\nE: could not read error message from server\n");
405 } else {
406 buf[rlen] = '\0';
407 fprintf(stderr, "Server said: %s\n", buf);
410 exit(EXIT_FAILURE);
411 } else {
412 if(reptype != NBD_REP_ACK) {
413 if(reptype != NBD_REP_SERVER) {
414 err("Server sent us a reply we don't understand!");
416 if(read(sock, &lenn, sizeof(lenn)) < 0) {
417 fprintf(stderr, "\nE: could not read export name length from server\n");
418 exit(EXIT_FAILURE);
420 lenn=ntohl(lenn);
421 if (lenn >= BUF_SIZE) {
422 fprintf(stderr, "\nE: export name on server too long\n");
423 exit(EXIT_FAILURE);
425 if(read(sock, buf, lenn) < 0) {
426 fprintf(stderr, "\nE: could not read export name from server\n");
427 exit(EXIT_FAILURE);
429 buf[lenn] = 0;
430 printf("%s", buf);
431 len -= lenn;
432 len -= sizeof(lenn);
433 if(len > 0) {
434 if(read(sock, buf, len) < 0) {
435 fprintf(stderr, "\nE: could not read export description from server\n");
436 exit(EXIT_FAILURE);
438 buf[len] = 0;
439 printf(": %s\n", buf);
440 } else {
441 printf("\n");
445 } while(reptype != NBD_REP_ACK);
446 send_request(sock, NBD_OPT_ABORT, 0, NULL);
449 void parse_sizes(char *buf, uint64_t *size, uint16_t *flags) {
450 memcpy(size, buf, sizeof(*size));
451 *size = ntohll(*size);
452 buf += sizeof(*size);
453 memcpy(flags, buf, sizeof(*flags));
454 *flags = ntohs(*flags);
456 if ((*size>>12) > (uint64_t)~0UL) {
457 printf("size = %luMB", (unsigned long)(*size>>20));
458 err("Exported device is too big for me. Get 64-bit machine :-(\n");
459 } else {
460 printf("size = %luMB", (unsigned long)(*size>>20));
462 printf("\n");
465 void send_opt_exportname(int sock, u64 *rsize64, uint16_t *flags, bool can_opt_go, char* name, uint16_t global_flags) {
466 send_request(sock, NBD_OPT_EXPORT_NAME, -1, name);
467 char b[sizeof(*flags) + sizeof(*rsize64)];
468 if(readit(sock, b, sizeof(b)) < 0 && can_opt_go) {
469 err("E: server does not support NBD_OPT_GO and dropped connection after sending NBD_OPT_EXPORT_NAME. Try -g.");
471 parse_sizes(b, rsize64, flags);
472 if(!global_flags & NBD_FLAG_NO_ZEROES) {
473 char buf[125];
474 readit(sock, buf, 124);
478 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, bool can_opt_go) {
479 u64 magic;
480 uint16_t tmp;
481 uint16_t global_flags;
482 char buf[256] = "\0\0\0\0\0\0\0\0\0";
483 int sock = *sockp;
485 printf("Negotiation: ");
486 readit(sock, buf, 8);
487 if (strcmp(buf, INIT_PASSWD))
488 err("INIT_PASSWD bad");
489 printf(".");
490 readit(sock, &magic, sizeof(magic));
491 magic = ntohll(magic);
492 if (magic != opts_magic) {
493 if(magic == cliserv_magic) {
494 err("It looks like you're trying to connect to an oldstyle server. This is no longer supported since nbd 3.10.");
497 printf(".");
498 readit(sock, &tmp, sizeof(uint16_t));
499 global_flags = ntohs(tmp);
500 if((needed_flags & global_flags) != needed_flags) {
501 /* There's currently really only one reason why this
502 * check could possibly fail, but we may need to change
503 * this error message in the future... */
504 fprintf(stderr, "\nE: Server does not support listing exports\n");
505 exit(EXIT_FAILURE);
508 if (global_flags & NBD_FLAG_NO_ZEROES) {
509 client_flags |= NBD_FLAG_C_NO_ZEROES;
511 client_flags = htonl(client_flags);
512 if (write(sock, &client_flags, sizeof(client_flags)) < 0)
513 err("Failed/2.1: %m");
515 #if HAVE_GNUTLS && !defined(NOTLS)
516 /* TLS */
517 if (tls) {
518 int plainfd[2]; // [0] is used by the proxy, [1] is used by NBD
519 tlssession_t *s = NULL;
520 int ret;
521 uint32_t tmp32;
522 uint64_t tmp64;
524 send_request(sock, NBD_OPT_STARTTLS, 0, NULL);
526 if (read(sock, &tmp64, sizeof(tmp64)) < 0)
527 err("Could not read cliserv_magic: %m");
528 tmp64 = ntohll(tmp64);
529 if (tmp64 != NBD_OPT_REPLY_MAGIC) {
530 err("reply magic does not match");
532 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
533 err("Could not read option type: %m");
534 tmp32 = ntohl(tmp32);
535 if (tmp32 != NBD_OPT_STARTTLS)
536 err("Reply to wrong option");
537 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
538 err("Could not read option reply type: %m");
539 tmp32 = ntohl(tmp32);
540 if (tmp32 != NBD_REP_ACK) {
541 err("Option reply type != NBD_REP_ACK");
543 if (read(sock, &tmp32, sizeof(tmp32)) < 0) err(
544 "Could not read option data length: %m");
545 tmp32 = ntohl(tmp32);
546 if (tmp32 != 0) {
547 err("Option reply data length != 0");
549 s = tlssession_new(0,
550 keyfile,
551 certfile,
552 cacertfile,
553 tlshostname,
554 !cacertfile || !tlshostname, // insecure flag
555 #ifdef DODBG
556 1, // debug
557 #else
558 0, // debug
559 #endif
560 NULL, // quitfn
561 NULL, // erroutfn
562 NULL // opaque
564 if (!s)
565 err("Cannot establish TLS session");
567 if (socketpair(AF_UNIX, SOCK_STREAM, 0, plainfd) < 0)
568 err("Cannot get socket pair");
570 if (set_nonblocking(plainfd[0], 0) <0 ||
571 set_nonblocking(plainfd[1], 0) <0 ||
572 set_nonblocking(sock, 0) <0) {
573 close(plainfd[0]);
574 close(plainfd[1]);
575 err("Cannot set socket options");
578 ret = fork();
579 if (ret < 0)
580 err("Could not fork");
581 else if (ret == 0) {
582 // we are the child
583 if (daemon(0, 0) < 0) {
584 /* no one will see this */
585 fprintf(stderr, "Can't detach from the terminal");
586 exit(1);
588 signal (SIGPIPE, SIG_IGN);
589 close(plainfd[1]);
590 tlssession_mainloop(sock, plainfd[0], s);
591 close(sock);
592 close(plainfd[0]);
593 exit(0);
595 close(plainfd[0]);
596 close(sock);
597 sock = plainfd[1]; /* use the decrypted FD from now on */
598 *sockp = sock;
600 #else
601 if (keyfile) {
602 err("TLS requested but support not compiled in");
604 #endif
606 if(do_opts & NBDC_DO_LIST) {
607 ask_list(sock);
608 exit(EXIT_SUCCESS);
611 struct reply *rep = NULL;
613 if(!can_opt_go) {
614 send_opt_exportname(sock, rsize64, flags, can_opt_go, name, global_flags);
615 return;
618 send_info_request(sock, NBD_OPT_GO, 0, NULL, name);
620 do {
621 if(rep != NULL) free(rep);
622 rep = read_reply(sock);
623 if(rep && (rep->reply_type & NBD_REP_FLAG_ERROR)) {
624 switch(rep->reply_type) {
625 case NBD_REP_ERR_UNSUP:
626 /* server doesn't support NBD_OPT_GO or NBD_OPT_INFO,
627 * fall back to NBD_OPT_EXPORT_NAME */
628 send_opt_exportname(sock, rsize64, flags, can_opt_go, name, global_flags);
629 free(rep);
630 return;
631 case NBD_REP_ERR_POLICY:
632 if(rep->datasize > 0) {
633 char errstr[1024];
634 snprintf(errstr, sizeof errstr, "Connection not allowed by server policy. Server said: %s", rep->data);
635 err(errstr);
636 } else {
637 err("Connection not allowed by server policy.");
639 free(rep);
640 exit(EXIT_FAILURE);
641 default:
642 if(rep->datasize > 0) {
643 char errstr[1024];
644 snprintf(errstr, sizeof errstr, "Unknown error returned by server. Server said: %s", rep->data);
645 err(errstr);
646 } else {
647 err("Unknown error returned by server.");
649 free(rep);
650 exit(EXIT_FAILURE);
653 uint16_t info_type;
654 switch(rep->reply_type) {
655 case NBD_REP_INFO:
656 memcpy(&info_type, rep->data, 2);
657 info_type = htons(info_type);
658 switch(info_type) {
659 case NBD_INFO_EXPORT:
660 parse_sizes(rep->data + 2, rsize64, flags);
661 break;
662 default:
663 // ignore these, don't need them
664 break;
666 break;
667 case NBD_REP_ACK:
668 break;
669 default:
670 err_nonfatal("Unknown reply to NBD_OPT_GO received, ignoring");
672 } while(rep->reply_type != NBD_REP_ACK);
673 free(rep);
676 bool get_from_config(char* cfgname, char** name_ptr, char** dev_ptr, char** hostn_ptr, int* bs, int* timeout, int* persist, int* swap, int* sdp, int* b_unix, char**port, int* num_conns, char **certfile, char **keyfile, char **cacertfile, char **tlshostname, bool *can_opt_go) {
677 int fd = open(SYSCONFDIR "/nbdtab", O_RDONLY);
678 bool retval = false;
679 if(fd < 0) {
680 fprintf(stderr, "while opening %s: ", SYSCONFDIR "/nbdtab");
681 perror("could not open config file");
682 goto out;
684 off_t size = lseek(fd, 0, SEEK_END);
685 lseek(fd, 0, SEEK_SET);
686 void *data = NULL;
687 char *fsep = "\n\t# ";
688 char *lsep = "\n#";
690 if(size < 0) {
691 perror("E: mmap'ing nbdtab");
692 exit(EXIT_FAILURE);
695 data = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED, fd, 0);
696 if(!strncmp(cfgname, "/dev/", 5)) {
697 cfgname += 5;
699 char *loc = strstr((const char*)data, cfgname);
700 if(!loc) {
701 goto out;
703 size_t l = strlen(cfgname) + 6;
704 *dev_ptr = malloc(l);
705 snprintf(*dev_ptr, l, "/dev/%s", cfgname);
707 size_t line_len, field_len, ws_len;
708 #define CHECK_LEN field_len = strcspn(loc, fsep); ws_len = strspn(loc+field_len, fsep); if(field_len > line_len || line_len <= 0) { goto out; }
709 #define MOVE_NEXT line_len -= field_len + ws_len; loc += field_len + ws_len
710 // find length of line
711 line_len = strcspn(loc, lsep);
712 // first field is the device node name, which we already know, so skip it
713 CHECK_LEN;
714 MOVE_NEXT;
715 // next field is the hostname
716 CHECK_LEN;
717 *hostn_ptr = strndup(loc, field_len);
718 MOVE_NEXT;
719 // third field is the export name
720 CHECK_LEN;
721 *name_ptr = strndup(loc, field_len);
722 if(ws_len + field_len > line_len) {
723 // optional last field is not there, so return success
724 retval = true;
725 goto out;
727 MOVE_NEXT;
728 CHECK_LEN;
729 #undef CHECK_LEN
730 #undef MOVE_NEXT
731 // fourth field is the options field, a comma-separated field of options
732 do {
733 if(!strncmp(loc, "conns=", 6)) {
734 *num_conns = (int)strtol(loc+6, &loc, 0);
735 goto next;
737 if(!strncmp(loc, "bs=", 3)) {
738 *bs = (int)strtol(loc+3, &loc, 0);
739 goto next;
741 if(!strncmp(loc, "timeout=", 8)) {
742 *timeout = (int)strtol(loc+8, &loc, 0);
743 goto next;
745 if(!strncmp(loc, "port=", 5)) {
746 *port = strndup(loc+5, strcspn(loc+5, ","));
747 goto next;
749 if(!strncmp(loc, "persist", 7)) {
750 loc += 7;
751 *persist = 1;
752 goto next;
754 if(!strncmp(loc, "swap", 4)) {
755 *swap = 1;
756 loc += 4;
757 goto next;
759 if(!strncmp(loc, "sdp", 3)) {
760 *sdp = 1;
761 loc += 3;
762 goto next;
764 if(!strncmp(loc, "unix", 4)) {
765 *b_unix = 1;
766 loc += 4;
767 goto next;
769 if(!strncmp(loc, "certfile=", 9)) {
770 *certfile = strndup(loc+9, strcspn(loc+9, ","));
771 goto next;
773 if(!strncmp(loc, "keyfile=", 8)) {
774 *keyfile = strndup(loc+8, strcspn(loc+8, ","));
775 goto next;
777 if(!strncmp(loc, "cacertfile=", 11)) {
778 *cacertfile = strndup(loc+11, strcspn(loc+11, ","));
779 goto next;
781 if(!strncmp(loc, "tlshostname=", 9)) {
782 *tlshostname = strndup(loc+9, strcspn(loc+9, ","));
783 goto next;
785 if(!strncmp(loc, "no_optgo", 8)) {
786 *can_opt_go = false;
787 goto next;
789 // skip unknown options, with a warning unless they start with a '_'
790 l = strcspn(loc, ",");
791 if(*loc != '_') {
792 char* s = strndup(loc, l);
793 fprintf(stderr, "Warning: unknown option '%s' found in nbdtab file", s);
794 free(s);
796 loc += l;
797 next:
798 if(*loc == ',') {
799 loc++;
801 } while(strcspn(loc, lsep) > 0);
802 retval = true;
803 out:
804 if(data != NULL) {
805 munmap(data, size);
807 if(fd >= 0) {
808 close(fd);
810 return retval;
813 void setsizes(int nbd, u64 size64, int blocksize, u32 flags) {
814 unsigned long size;
815 int read_only = (flags & NBD_FLAG_READ_ONLY) ? 1 : 0;
817 if (size64>>12 > (uint64_t)~0UL)
818 err("Device too large.\n");
819 else {
820 int tmp_blocksize = 4096;
821 if (size64 / (u64)blocksize <= (uint64_t)~0UL)
822 tmp_blocksize = blocksize;
823 if (ioctl(nbd, NBD_SET_BLKSIZE, tmp_blocksize) < 0) {
824 fprintf(stderr, "Failed to set blocksize %d\n",
825 tmp_blocksize);
826 err("Ioctl/1.1a failed: %m\n");
828 size = (unsigned long)(size64 / (u64)tmp_blocksize);
829 if (ioctl(nbd, NBD_SET_SIZE_BLOCKS, size) < 0)
830 err("Ioctl/1.1b failed: %m\n");
831 if (tmp_blocksize != blocksize) {
832 if (ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long)blocksize) < 0) {
833 fprintf(stderr, "Failed to set blocksize %d\n",
834 blocksize);
835 err("Ioctl/1.1c failed: %m\n");
838 fprintf(stderr, "bs=%d, sz=%" PRIu64 " bytes\n", blocksize, (u64)tmp_blocksize * size);
841 ioctl(nbd, NBD_CLEAR_SOCK);
843 /* ignore error as kernel may not support */
844 ioctl(nbd, NBD_SET_FLAGS, (unsigned long) flags);
846 if (ioctl(nbd, BLKROSET, (unsigned long) &read_only) < 0)
847 err("Unable to set read-only attribute for device");
850 void set_timeout(int nbd, int timeout) {
851 if (timeout) {
852 if (ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long)timeout) < 0)
853 err("Ioctl NBD_SET_TIMEOUT failed: %m\n");
854 fprintf(stderr, "timeout=%d\n", timeout);
858 void finish_sock(int sock, int nbd, int swap) {
859 if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) {
860 if (errno == EBUSY)
861 err("Kernel doesn't support multiple connections\n");
862 else
863 err("Ioctl NBD_SET_SOCK failed: %m\n");
866 #ifndef __ANDROID__
867 if (swap)
868 mlockall(MCL_CURRENT | MCL_FUTURE);
869 #endif
872 static int
873 oom_adjust(const char *file, const char *value)
875 int fd, rc;
876 size_t len;
878 fd = open(file, O_WRONLY);
879 if (fd < 0)
880 return -1;
881 len = strlen(value);
882 rc = write(fd, value, len) != (ssize_t) len;
883 close(fd);
884 return rc ? -1 : 0;
887 void usage(char* errmsg, ...) {
888 if(errmsg) {
889 char tmp[256];
890 va_list ap;
891 va_start(ap, errmsg);
892 snprintf(tmp, 256, "ERROR: %s\n\n", errmsg);
893 vfprintf(stderr, tmp, ap);
894 va_end(ap);
895 } else {
896 fprintf(stderr, "%s version %s\n", PROG_NAME, PACKAGE_VERSION);
898 #if HAVE_NETLINK
899 fprintf(stderr, "Usage: nbd-client -name|-N name host [port] nbd_device\n\t[-block-size|-b block size] [-timeout|-t timeout] [-swap|-s] [-sdp|-S]\n\t[-persist|-p] [-nofork|-n] [-systemd-mark|-m] [-nonetlink|-L]\n");
900 #else
901 fprintf(stderr, "Usage: nbd-client -name|-N name host [port] nbd_device\n\t[-block-size|-b block size] [-timeout|-t timeout] [-swap|-s] [-sdp|-S]\n\t[-persist|-p] [-nofork|-n] [-systemd-mark|-m]\n");
902 #endif
903 fprintf(stderr, "Or : nbd-client -u (with same arguments as above)\n");
904 fprintf(stderr, "Or : nbd-client nbdX\n");
905 fprintf(stderr, "Or : nbd-client -d nbd_device\n");
906 fprintf(stderr, "Or : nbd-client -c nbd_device\n");
907 fprintf(stderr, "Or : nbd-client -h|--help\n");
908 fprintf(stderr, "Or : nbd-client -l|--list host\n");
909 fprintf(stderr, "Or : nbd-client -V|--version\n");
910 #if HAVE_GNUTLS && !defined(NOTLS)
911 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");
912 #endif
913 fprintf(stderr, "Default value for blocksize is 1024 (recommended for ethernet)\n");
914 fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */
915 fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n");
916 fprintf(stderr, "blocksizes other than 1024 without patches\n");
917 fprintf(stderr, "Default value for port is 10809. Note that port must always be numeric\n");
918 fprintf(stderr, "Bug reports and general discussion should go to %s\n", PACKAGE_BUGREPORT);
921 void disconnect(char* device) {
922 int nbd = open(device, O_RDWR);
924 if (nbd < 0)
925 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
926 printf("disconnect, ");
927 if (ioctl(nbd, NBD_DISCONNECT)<0)
928 err("Ioctl failed: %m\n");
929 printf("sock, ");
930 if (ioctl(nbd, NBD_CLEAR_SOCK)<0)
931 err("Ioctl failed: %m\n");
932 printf("done\n");
935 #if HAVE_NETLINK
936 static const char *short_opts = "-A:b:c:C:d:H:hK:LlnN:pSst:uVx";
937 #else
938 static const char *short_opts = "-A:b:c:C:d:gH:hK:lnN:pSst:uVx";
939 #endif
941 int main(int argc, char *argv[]) {
942 char* port=NBD_DEFAULT_PORT;
943 int sock, nbd;
944 int blocksize=1024;
945 char *hostname=NULL;
946 char *nbddev=NULL;
947 int swap=0;
948 int cont=0;
949 int timeout=0;
950 int sdp=0;
951 int G_GNUC_UNUSED nofork=0; // if -dNOFORK
952 pid_t main_pid;
953 u64 size64;
954 uint16_t flags = 0;
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 bool tls = false;
968 struct sigaction sa;
969 int num_connections = 1;
970 int netlink = HAVE_NETLINK;
971 int need_disconnect = 0;
972 int *sockfds;
973 struct option long_options[] = {
974 { "cacertfile", required_argument, NULL, 'A' },
975 { "block-size", required_argument, NULL, 'b' },
976 { "check", required_argument, NULL, 'c' },
977 { "connections", required_argument, NULL, 'C'},
978 { "disconnect", required_argument, NULL, 'd' },
979 { "certfile", required_argument, NULL, 'F' },
980 { "no-optgo", no_argument, NULL, 'g' },
981 { "help", no_argument, NULL, 'h' },
982 { "tlshostname", required_argument, NULL, 'H' },
983 { "keyfile", required_argument, NULL, 'K' },
984 { "list", no_argument, NULL, 'l' },
985 #if HAVE_NETLINK
986 { "nonetlink", no_argument, NULL, 'L' },
987 #endif
988 { "systemd-mark", no_argument, NULL, 'm' },
989 { "nofork", no_argument, NULL, 'n' },
990 { "name", required_argument, NULL, 'N' },
991 { "persist", no_argument, NULL, 'p' },
992 { "sdp", no_argument, NULL, 'S' },
993 { "swap", no_argument, NULL, 's' },
994 { "timeout", required_argument, NULL, 't' },
995 { "unix", no_argument, NULL, 'u' },
996 { "version", no_argument, NULL, 'V' },
997 { "enable-tls", no_argument, NULL, 'x' },
998 { 0, 0, 0, 0 },
1000 int i;
1001 bool can_opt_go = true;
1003 logging(MY_NAME);
1005 #if HAVE_GNUTLS && !defined(NOTLS)
1006 tlssession_init();
1007 #endif
1009 while((c=getopt_long_only(argc, argv, short_opts, long_options, NULL))>=0) {
1010 switch(c) {
1011 case 1:
1012 // non-option argument
1013 if(strchr(optarg, '=')) {
1014 // old-style 'bs=' or 'timeout='
1015 // argument
1016 fprintf(stderr, "WARNING: old-style command-line argument encountered. This is deprecated.\n");
1017 if(!strncmp(optarg, "bs=", 3)) {
1018 optarg+=3;
1019 goto blocksize;
1021 if(!strncmp(optarg, "timeout=", 8)) {
1022 optarg+=8;
1023 goto timeout;
1025 usage("unknown option %s encountered", optarg);
1026 exit(EXIT_FAILURE);
1028 switch(nonspecial++) {
1029 case 0:
1030 // host
1031 hostname=optarg;
1032 break;
1033 case 1:
1034 // port
1035 if(!strtol(optarg, NULL, 0)) {
1036 // not parseable as a number, assume it's the device
1037 nbddev = optarg;
1038 nonspecial++;
1039 } else {
1040 port = optarg;
1042 break;
1043 case 2:
1044 // device
1045 nbddev = optarg;
1046 break;
1047 default:
1048 usage("too many non-option arguments specified");
1049 exit(EXIT_FAILURE);
1051 break;
1052 case 'b':
1053 blocksize:
1054 blocksize=(int)strtol(optarg, NULL, 0);
1055 break;
1056 case 'c':
1057 return check_conn(optarg, 1);
1058 case 'C':
1059 num_connections = (int)strtol(optarg, NULL, 0);
1060 break;
1061 case 'd':
1062 need_disconnect = 1;
1063 nbddev = strdup(optarg);
1064 break;
1065 case 'g':
1066 can_opt_go = false;
1067 break;
1068 case 'h':
1069 usage(NULL);
1070 exit(EXIT_SUCCESS);
1071 case 'l':
1072 needed_flags |= NBD_FLAG_FIXED_NEWSTYLE;
1073 opts |= NBDC_DO_LIST;
1074 nbddev="";
1075 break;
1076 #if HAVE_NETLINK
1077 case 'L':
1078 netlink = 0;
1079 break;
1080 #endif
1081 case 'm':
1082 argv[0][0] = '@';
1083 break;
1084 case 'n':
1085 nofork=1;
1086 break;
1087 case 'N':
1088 name=optarg;
1089 break;
1090 case 'p':
1091 cont=1;
1092 break;
1093 case 's':
1094 swap=1;
1095 break;
1096 case 'S':
1097 sdp=1;
1098 break;
1099 case 't':
1100 timeout:
1101 timeout=strtol(optarg, NULL, 0);
1102 break;
1103 case 'u':
1104 b_unix = 1;
1105 break;
1106 case 'V':
1107 printf("This is %s, from %s\n", PROG_NAME, PACKAGE_STRING);
1108 return 0;
1109 #if HAVE_GNUTLS && !defined(NOTLS)
1110 case 'x':
1111 tls = true;
1112 break;
1113 case 'F':
1114 certfile=strdup(optarg);
1115 break;
1116 case 'K':
1117 keyfile=strdup(optarg);
1118 break;
1119 case 'A':
1120 cacertfile=strdup(optarg);
1121 break;
1122 case 'H':
1123 tlshostname=strdup(optarg);
1124 break;
1125 #else
1126 case 'F':
1127 case 'K':
1128 case 'H':
1129 case 'A':
1130 fprintf(stderr, "E: TLS support not compiled in\n");
1131 exit(EXIT_FAILURE);
1132 #endif
1133 default:
1134 fprintf(stderr, "E: option eaten by 42 mice\n");
1135 exit(EXIT_FAILURE);
1139 if (need_disconnect) {
1140 if (netlink)
1141 netlink_disconnect(nbddev);
1142 else
1143 disconnect(nbddev);
1144 exit(EXIT_SUCCESS);
1146 #ifdef __ANDROID__
1147 if (swap)
1148 err("swap option unsupported on Android because mlockall is unsupported.");
1149 #endif
1150 if(hostname) {
1151 if((!name || !nbddev) && !(opts & NBDC_DO_LIST)) {
1152 if(!strncmp(hostname, "nbd", 3) || !strncmp(hostname, "/dev/nbd", 8)) {
1153 if(!get_from_config(hostname, &name, &nbddev, &hostname, &blocksize, &timeout, &cont, &swap, &sdp, &b_unix, &port, &num_connections, &certfile, &keyfile, &cacertfile, &hostname, &can_opt_go)) {
1154 usage("no valid configuration for specified device found", hostname);
1155 exit(EXIT_FAILURE);
1157 } else if (!netlink) {
1158 usage("not enough information specified, and argument didn't look like an nbd device");
1159 exit(EXIT_FAILURE);
1162 } else {
1163 usage("no information specified");
1164 exit(EXIT_FAILURE);
1167 if (keyfile && !certfile)
1168 certfile = strdup(keyfile);
1170 if (certfile != NULL || keyfile != NULL || cacertfile != NULL || tlshostname != NULL) {
1171 tls = true;
1174 if (!tlshostname && hostname)
1175 tlshostname = strdup(hostname);
1177 if (netlink)
1178 nofork = 1;
1180 if(strlen(name)==0 && !(opts & NBDC_DO_LIST)) {
1181 printf("Warning: the oldstyle protocol is no longer supported.\nThis method now uses the newstyle protocol with a default export\n");
1184 if(!(opts & NBDC_DO_LIST) && !netlink) {
1185 nbd = open(nbddev, O_RDWR);
1186 if (nbd < 0)
1187 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
1190 if (netlink) {
1191 sockfds = malloc(sizeof(int) * num_connections);
1192 if (!sockfds)
1193 err("Cannot allocate the socket fd's array");
1196 for (i = 0; i < num_connections; i++) {
1197 if (b_unix)
1198 sock = openunix(hostname);
1199 else
1200 sock = opennet(hostname, port, sdp);
1201 if (sock < 0)
1202 exit(EXIT_FAILURE);
1204 negotiate(&sock, &size64, &flags, name, needed_flags, cflags, opts, certfile, keyfile, cacertfile, tlshostname, tls, can_opt_go);
1205 if (netlink) {
1206 sockfds[i] = sock;
1207 continue;
1210 if (i == 0) {
1211 setsizes(nbd, size64, blocksize, flags);
1212 set_timeout(nbd, timeout);
1214 finish_sock(sock, nbd, swap);
1215 if (swap) {
1216 if (keyfile)
1217 fprintf(stderr, "Warning: using swap and TLS is prone to deadlock\n");
1218 /* try linux >= 2.6.36 interface first */
1219 if (oom_adjust("/proc/self/oom_score_adj", "-1000")) {
1220 /* fall back to linux <= 2.6.35 interface */
1221 oom_adjust("/proc/self/oom_adj", "-17");
1226 if (netlink) {
1227 int index = -1;
1228 if (nbddev) {
1229 if (sscanf(nbddev, "/dev/nbd%d", &index) != 1)
1230 err("Invalid nbd device target\n");
1232 netlink_configure(index, sockfds, num_connections,
1233 size64, blocksize, flags, timeout);
1234 return 0;
1236 /* Go daemon */
1238 #ifndef NOFORK
1239 if(!nofork) {
1240 if (daemon(0,0) < 0)
1241 err("Cannot detach from terminal");
1244 memset(&sa, 0, sizeof(sa));
1245 sa.sa_handler = SIG_IGN;
1246 sigaction(SIGCHLD, &sa, NULL);
1247 #endif
1248 /* For child to check its parent */
1249 main_pid = getpid();
1250 do {
1251 #ifndef NOFORK
1253 sigfillset(&block);
1254 sigdelset(&block, SIGKILL);
1255 sigdelset(&block, SIGTERM);
1256 sigdelset(&block, SIGPIPE);
1257 sigprocmask(SIG_SETMASK, &block, &old);
1259 if (!fork()) {
1260 /* Due to a race, the kernel NBD driver cannot
1261 * call for a reread of the partition table
1262 * in the handling of the NBD_DO_IT ioctl().
1263 * Therefore, this is done in the first open()
1264 * of the device. We therefore make sure that
1265 * the device is opened at least once after the
1266 * connection was made. This has to be done in a
1267 * separate process, since the NBD_DO_IT ioctl()
1268 * does not return until the NBD device has
1269 * disconnected.
1271 struct timespec req = {
1272 .tv_sec = 0,
1273 .tv_nsec = 100000000,
1275 while(check_conn(nbddev, 0)) {
1276 if (main_pid != getppid()) {
1277 /* check_conn() will not return 0 when nbd disconnected
1278 * and parent exited during this loop. So the child has to
1279 * explicitly check parent identity and exit if parent
1280 * exited */
1281 exit(0);
1283 nanosleep(&req, NULL);
1285 if(open(nbddev, O_RDONLY) < 0) {
1286 perror("could not open device for updating partition table");
1288 exit(0);
1290 #endif
1292 if (ioctl(nbd, NBD_DO_IT) < 0) {
1293 int error = errno;
1294 fprintf(stderr, "nbd,%d: Kernel call returned: %s\n", main_pid, strerror(errno));
1295 if(error==EBADR) {
1296 /* The user probably did 'nbd-client -d' on us.
1297 * quit */
1298 cont=0;
1299 } else {
1300 if(cont) {
1301 u64 new_size;
1302 uint16_t new_flags;
1304 close(sock); close(nbd);
1305 for (;;) {
1306 fprintf(stderr, " Reconnecting\n");
1307 if (b_unix)
1308 sock = openunix(hostname);
1309 else
1310 sock = opennet(hostname, port, sdp);
1311 if (sock >= 0)
1312 break;
1313 sleep (1);
1315 nbd = open(nbddev, O_RDWR);
1316 if (nbd < 0)
1317 err("Cannot open NBD: %m");
1318 negotiate(&sock, &new_size, &new_flags, name, needed_flags, cflags, opts, certfile, keyfile, cacertfile, tlshostname, tls, can_opt_go);
1319 if (size64 != new_size) {
1320 err("Size of the device changed. Bye");
1322 setsizes(nbd, size64, blocksize,
1323 new_flags);
1325 set_timeout(nbd, timeout);
1326 finish_sock(sock,nbd,swap);
1329 } else {
1330 /* We're on 2.4. It's not clearly defined what exactly
1331 * happened at this point. Probably best to quit, now
1333 fprintf(stderr, "Kernel call returned.\n");
1334 cont=0;
1336 } while(cont);
1337 printf("sock, ");
1338 ioctl(nbd, NBD_CLEAR_SOCK);
1339 printf("done\n");
1340 return 0;