Unbreak the cherry-pick
[nbd.git] / nbd-client.c
blob5404defbc9cb951611a5c6608773ed2af9dbd186
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>
48 #define MY_NAME "nbd_client"
49 #include "cliserv.h"
51 #if HAVE_GNUTLS && !defined(NOTLS)
52 #include "crypto-gnutls.h"
53 #endif
55 #ifdef WITH_SDP
56 #include <sdp_inet.h>
57 #endif
59 #define NBDC_DO_LIST 1
61 int check_conn(char* devname, int do_print) {
62 char buf[256];
63 char* p;
64 int fd;
65 int len;
67 if( (p=strrchr(devname, '/')) ) {
68 devname=p+1;
70 if((p=strchr(devname, 'p'))) {
71 /* We can't do checks on partitions. */
72 *p='\0';
74 snprintf(buf, 256, "/sys/block/%s/pid", devname);
75 if((fd=open(buf, O_RDONLY))<0) {
76 if(errno==ENOENT) {
77 return 1;
78 } else {
79 return 2;
82 len=read(fd, buf, 256);
83 if(len < 0) {
84 perror("could not read from server");
85 close(fd);
86 return 2;
88 buf[(len < 256) ? len : 255]='\0';
89 if(do_print) printf("%s\n", buf);
90 close(fd);
91 return 0;
94 int opennet(char *name, char* portstr, int sdp) {
95 int sock;
96 struct addrinfo hints;
97 struct addrinfo *ai = NULL;
98 struct addrinfo *rp = NULL;
99 int e;
101 memset(&hints,'\0',sizeof(hints));
102 hints.ai_family = AF_UNSPEC;
103 hints.ai_socktype = SOCK_STREAM;
104 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
105 hints.ai_protocol = IPPROTO_TCP;
107 e = getaddrinfo(name, portstr, &hints, &ai);
109 if(e != 0) {
110 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
111 freeaddrinfo(ai);
112 return -1;
115 if(sdp) {
116 #ifdef WITH_SDP
117 if (ai->ai_family == AF_INET)
118 ai->ai_family = AF_INET_SDP;
119 else (ai->ai_family == AF_INET6)
120 ai->ai_family = AF_INET6_SDP;
121 #else
122 err("Can't do SDP: I was not compiled with SDP support!");
123 #endif
126 for(rp = ai; rp != NULL; rp = rp->ai_next) {
127 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
129 if(sock == -1)
130 continue; /* error */
132 if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
133 break; /* success */
135 close(sock);
138 if (rp == NULL) {
139 err_nonfatal("Socket failed: %m");
140 sock = -1;
141 goto err;
144 setmysockopt(sock);
145 err:
146 freeaddrinfo(ai);
147 return sock;
150 int openunix(const char *path) {
151 int sock;
152 struct sockaddr_un un_addr;
153 memset(&un_addr, 0, sizeof(un_addr));
155 un_addr.sun_family = AF_UNIX;
156 if (strnlen(path, sizeof(un_addr.sun_path)) == sizeof(un_addr.sun_path)) {
157 err_nonfatal("UNIX socket path too long");
158 return -1;
161 strncpy(un_addr.sun_path, path, sizeof(un_addr.sun_path) - 1);
163 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
164 err_nonfatal("SOCKET failed");
165 return -1;
168 if (connect(sock, &un_addr, sizeof(un_addr)) == -1) {
169 err_nonfatal("CONNECT failed");
170 close(sock);
171 return -1;
173 return sock;
176 void send_request(int sock, uint32_t opt, ssize_t datasize, void* data) {
177 struct {
178 uint64_t magic;
179 uint32_t opt;
180 uint32_t datasize;
181 } __attribute__((packed)) header = {
182 ntohll(opts_magic),
183 ntohl(opt),
184 ntohl(datasize),
186 if(datasize < 0) {
187 datasize = strlen((char*)data);
188 header.datasize = htonl(datasize);
190 writeit(sock, &header, sizeof(header));
191 if(data != NULL) {
192 writeit(sock, data, datasize);
196 void send_info_request(int sock, uint32_t opt, int n_reqs, uint16_t* reqs, char* name) {
197 uint16_t rlen = htons(n_reqs);
198 uint32_t nlen = htonl(strlen(name));
200 send_request(sock, opt, sizeof(uint32_t) + strlen(name) + sizeof(uint16_t) + n_reqs * sizeof(uint16_t), NULL);
201 writeit(sock, &nlen, sizeof(nlen));
202 writeit(sock, name, strlen(name));
203 writeit(sock, &rlen, sizeof(rlen));
204 if(n_reqs > 0) {
205 writeit(sock, reqs, n_reqs * sizeof(uint16_t));
209 struct reply {
210 uint64_t magic;
211 uint32_t opt;
212 uint32_t reply_type;
213 uint32_t datasize;
214 char data[];
215 } __attribute__((packed));
217 struct reply* read_reply(int sock) {
218 struct reply *retval = malloc(sizeof(struct reply));
219 readit(sock, retval, sizeof(*retval));
220 retval->magic = ntohll(retval->magic);
221 retval->opt = ntohl(retval->opt);
222 retval->reply_type = ntohl(retval->reply_type);
223 retval->datasize = ntohl(retval->datasize);
224 if (retval->magic != rep_magic) {
225 fprintf(stderr, "E: received invalid negotiation magic %" PRIu64 " (expected %" PRIu64 ")", retval->magic, rep_magic);
226 exit(EXIT_FAILURE);
228 if (retval->datasize > 0) {
229 retval = realloc(retval, sizeof(struct reply) + retval->datasize);
230 readit(sock, &(retval->data), retval->datasize);
232 return retval;
235 void ask_list(int sock) {
236 uint32_t opt;
237 uint32_t opt_server;
238 uint32_t len;
239 uint32_t lenn;
240 uint32_t reptype;
241 uint64_t magic;
242 int rlen;
243 const int BUF_SIZE = 1024;
244 char buf[BUF_SIZE];
246 send_request(sock, NBD_OPT_LIST, 0, NULL);
247 /* newline, move away from the "Negotiation:" line */
248 printf("\n");
249 do {
250 memset(buf, 0, 1024);
251 if(read(sock, &magic, sizeof(magic)) < 0) {
252 err("Reading magic from server: %m");
254 if(read(sock, &opt_server, sizeof(opt_server)) < 0) {
255 err("Reading option: %m");
257 if(read(sock, &reptype, sizeof(reptype)) <0) {
258 err("Reading reply from server: %m");
260 if(read(sock, &len, sizeof(len)) < 0) {
261 err("Reading length from server: %m");
263 magic=ntohll(magic);
264 len=ntohl(len);
265 reptype=ntohl(reptype);
266 if(magic != rep_magic) {
267 err("Not enough magic from server");
269 if(reptype & NBD_REP_FLAG_ERROR) {
270 switch(reptype) {
271 case NBD_REP_ERR_POLICY:
272 fprintf(stderr, "\nE: listing not allowed by server.\n");
273 break;
274 default:
275 fprintf(stderr, "\nE: unexpected error from server.\n");
276 break;
278 if(len > 0 && len < BUF_SIZE) {
279 if((rlen=read(sock, buf, len)) < 0) {
280 fprintf(stderr, "\nE: could not read error message from server\n");
281 } else {
282 buf[rlen] = '\0';
283 fprintf(stderr, "Server said: %s\n", buf);
286 exit(EXIT_FAILURE);
287 } else {
288 if(reptype != NBD_REP_ACK) {
289 if(reptype != NBD_REP_SERVER) {
290 err("Server sent us a reply we don't understand!");
292 if(read(sock, &lenn, sizeof(lenn)) < 0) {
293 fprintf(stderr, "\nE: could not read export name length from server\n");
294 exit(EXIT_FAILURE);
296 lenn=ntohl(lenn);
297 if (lenn >= BUF_SIZE) {
298 fprintf(stderr, "\nE: export name on server too long\n");
299 exit(EXIT_FAILURE);
301 if(read(sock, buf, lenn) < 0) {
302 fprintf(stderr, "\nE: could not read export name from server\n");
303 exit(EXIT_FAILURE);
305 buf[lenn] = 0;
306 printf("%s", buf);
307 len -= lenn;
308 len -= sizeof(lenn);
309 if(len > 0) {
310 if(read(sock, buf, len) < 0) {
311 fprintf(stderr, "\nE: could not read export description from server\n");
312 exit(EXIT_FAILURE);
314 buf[len] = 0;
315 printf(": %s\n", buf);
316 } else {
317 printf("\n");
321 } while(reptype != NBD_REP_ACK);
322 send_request(sock, NBD_OPT_ABORT, 0, NULL);
325 void parse_sizes(char *buf, uint64_t *size, uint16_t *flags) {
326 memcpy(size, buf, sizeof(*size));
327 *size = ntohll(*size);
328 buf += sizeof(size);
329 memcpy(flags, buf, sizeof(*flags));
330 *flags = ntohs(*flags);
332 if ((*size>>12) > (uint64_t)~0UL) {
333 printf("size = %luMB", (unsigned long)(*size>>20));
334 err("Exported device is too big for me. Get 64-bit machine :-(\n");
335 } else {
336 printf("size = %luMB", (unsigned long)(*size>>20));
338 printf("\n");
341 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) {
342 u64 magic;
343 uint16_t tmp;
344 uint16_t global_flags;
345 char buf[256] = "\0\0\0\0\0\0\0\0\0";
346 uint32_t opt;
347 uint32_t namesize;
348 int sock = *sockp;
350 printf("Negotiation: ");
351 readit(sock, buf, 8);
352 if (strcmp(buf, INIT_PASSWD))
353 err("INIT_PASSWD bad");
354 printf(".");
355 readit(sock, &magic, sizeof(magic));
356 magic = ntohll(magic);
357 if (magic != opts_magic) {
358 if(magic == cliserv_magic) {
359 err("It looks like you're trying to connect to an oldstyle server. This is no longer supported since nbd 3.10.");
362 printf(".");
363 readit(sock, &tmp, sizeof(uint16_t));
364 global_flags = ntohs(tmp);
365 if((needed_flags & global_flags) != needed_flags) {
366 /* There's currently really only one reason why this
367 * check could possibly fail, but we may need to change
368 * this error message in the future... */
369 fprintf(stderr, "\nE: Server does not support listing exports\n");
370 exit(EXIT_FAILURE);
373 if (global_flags & NBD_FLAG_NO_ZEROES) {
374 client_flags |= NBD_FLAG_C_NO_ZEROES;
376 client_flags = htonl(client_flags);
377 if (write(sock, &client_flags, sizeof(client_flags)) < 0)
378 err("Failed/2.1: %m");
380 #if HAVE_GNUTLS && !defined(NOTLS)
381 /* TLS */
382 if (tls) {
383 int plainfd[2]; // [0] is used by the proxy, [1] is used by NBD
384 tlssession_t *s = NULL;
385 int ret;
386 uint32_t tmp32;
387 uint64_t tmp64;
389 send_request(sock, NBD_OPT_STARTTLS, 0, NULL);
391 if (read(sock, &tmp64, sizeof(tmp64)) < 0)
392 err("Could not read cliserv_magic: %m");
393 tmp64 = ntohll(tmp64);
394 if (tmp64 != NBD_OPT_REPLY_MAGIC) {
395 err("reply magic does not match");
397 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
398 err("Could not read option type: %m");
399 tmp32 = ntohl(tmp32);
400 if (tmp32 != NBD_OPT_STARTTLS)
401 err("Reply to wrong option");
402 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
403 err("Could not read option reply type: %m");
404 tmp32 = ntohl(tmp32);
405 if (tmp32 != NBD_REP_ACK) {
406 err("Option reply type != NBD_REP_ACK");
408 if (read(sock, &tmp32, sizeof(tmp32)) < 0) err(
409 "Could not read option data length: %m");
410 tmp32 = ntohl(tmp32);
411 if (tmp32 != 0) {
412 err("Option reply data length != 0");
414 s = tlssession_new(0,
415 keyfile,
416 certfile,
417 cacertfile,
418 tlshostname,
419 !cacertfile || !tlshostname, // insecure flag
420 #ifdef DODBG
421 1, // debug
422 #else
423 0, // debug
424 #endif
425 NULL, // quitfn
426 NULL, // erroutfn
427 NULL // opaque
429 if (!s)
430 err("Cannot establish TLS session");
432 if (socketpair(AF_UNIX, SOCK_STREAM, 0, plainfd) < 0)
433 err("Cannot get socket pair");
435 if (set_nonblocking(plainfd[0], 0) <0 ||
436 set_nonblocking(plainfd[1], 0) <0 ||
437 set_nonblocking(sock, 0) <0) {
438 close(plainfd[0]);
439 close(plainfd[1]);
440 err("Cannot set socket options");
443 ret = fork();
444 if (ret < 0)
445 err("Could not fork");
446 else if (ret == 0) {
447 // we are the child
448 if (daemon(0, 0) < 0) {
449 /* no one will see this */
450 fprintf(stderr, "Can't detach from the terminal");
451 exit(1);
453 signal (SIGPIPE, SIG_IGN);
454 close(plainfd[1]);
455 tlssession_mainloop(sock, plainfd[0], s);
456 close(sock);
457 close(plainfd[0]);
458 exit(0);
460 close(plainfd[0]);
461 close(sock);
462 sock = plainfd[1]; /* use the decrypted FD from now on */
463 *sockp = sock;
465 #else
466 if (keyfile) {
467 err("TLS requested but support not compiled in");
469 #endif
471 if(do_opts & NBDC_DO_LIST) {
472 ask_list(sock);
473 exit(EXIT_SUCCESS);
476 send_info_request(sock, NBD_OPT_GO, 0, NULL, name);
478 struct reply *rep = NULL;
480 do {
481 if(rep != NULL) free(rep);
482 rep = read_reply(sock);
483 if(rep->reply_type & NBD_REP_FLAG_ERROR) {
484 if(rep->reply_type == NBD_REP_ERR_UNSUP) {
485 free(rep);
486 /* server doesn't support NBD_OPT_GO or NBD_OPT_INFO,
487 * fall back to NBD_OPT_EXPORT_NAME */
488 send_request(sock, NBD_OPT_EXPORT_NAME, -1, name);
489 char b[sizeof(*flags) + sizeof(*rsize64)];
490 readit(sock, b, sizeof(b));
491 parse_sizes(b, rsize64, flags);
492 if(!(global_flags & NBD_FLAG_NO_ZEROES)) {
493 readit(sock, buf, 124);
495 return;
496 } else {
497 err("Unknown error in reply to NBD_OPT_GO; cannot continue");
498 exit(EXIT_FAILURE);
501 uint16_t info_type;
502 switch(rep->reply_type) {
503 case NBD_REP_INFO:
504 memcpy(&info_type, rep->data, 2);
505 info_type = htons(info_type);
506 switch(info_type) {
507 case NBD_INFO_EXPORT:
508 parse_sizes(rep->data + 2, rsize64, flags);
509 break;
510 default:
511 // ignore these, don't need them
512 break;
514 break;
515 case NBD_REP_ACK:
516 break;
517 default:
518 err_nonfatal("Unknown reply to NBD_OPT_GO received");
520 } while(rep->reply_type != NBD_REP_ACK);
521 free(rep);
524 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) {
525 int fd = open(SYSCONFDIR "/nbdtab", O_RDONLY);
526 bool retval = false;
527 if(fd < 0) {
528 fprintf(stderr, "while opening %s: ", SYSCONFDIR "/nbdtab");
529 perror("could not open config file");
530 goto out;
532 off_t size = lseek(fd, 0, SEEK_END);
533 lseek(fd, 0, SEEK_SET);
534 void *data = NULL;
535 char *fsep = "\n\t# ";
536 char *lsep = "\n#";
538 if(size < 0) {
539 perror("E: mmap'ing nbdtab");
540 exit(EXIT_FAILURE);
543 data = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED, fd, 0);
544 if(!strncmp(cfgname, "/dev/", 5)) {
545 cfgname += 5;
547 char *loc = strstr((const char*)data, cfgname);
548 if(!loc) {
549 goto out;
551 size_t l = strlen(cfgname) + 6;
552 *dev_ptr = malloc(l);
553 snprintf(*dev_ptr, l, "/dev/%s", cfgname);
555 size_t line_len, field_len, ws_len;
556 #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; }
557 #define MOVE_NEXT line_len -= field_len + ws_len; loc += field_len + ws_len
558 // find length of line
559 line_len = strcspn(loc, lsep);
560 // first field is the device node name, which we already know, so skip it
561 CHECK_LEN;
562 MOVE_NEXT;
563 // next field is the hostname
564 CHECK_LEN;
565 *hostn_ptr = strndup(loc, field_len);
566 MOVE_NEXT;
567 // third field is the export name
568 CHECK_LEN;
569 *name_ptr = strndup(loc, field_len);
570 if(ws_len + field_len > line_len) {
571 // optional last field is not there, so return success
572 retval = true;
573 goto out;
575 MOVE_NEXT;
576 CHECK_LEN;
577 #undef CHECK_LEN
578 #undef MOVE_NEXT
579 // fourth field is the options field, a comma-separated field of options
580 do {
581 if(!strncmp(loc, "conns=", 6)) {
582 *num_conns = (int)strtol(loc+6, &loc, 0);
583 goto next;
585 if(!strncmp(loc, "bs=", 3)) {
586 *bs = (int)strtol(loc+3, &loc, 0);
587 goto next;
589 if(!strncmp(loc, "timeout=", 8)) {
590 *timeout = (int)strtol(loc+8, &loc, 0);
591 goto next;
593 if(!strncmp(loc, "port=", 5)) {
594 *port = strndup(loc+5, strcspn(loc+5, ","));
595 goto next;
597 if(!strncmp(loc, "persist", 7)) {
598 loc += 7;
599 *persist = 1;
600 goto next;
602 if(!strncmp(loc, "swap", 4)) {
603 *swap = 1;
604 loc += 4;
605 goto next;
607 if(!strncmp(loc, "sdp", 3)) {
608 *sdp = 1;
609 loc += 3;
610 goto next;
612 if(!strncmp(loc, "unix", 4)) {
613 *b_unix = 1;
614 loc += 4;
615 goto next;
617 if(!strncmp(loc, "certfile=", 9)) {
618 *certfile = strndup(loc+9, strcspn(loc+9, ","));
619 goto next;
621 if(!strncmp(loc, "keyfile=", 8)) {
622 *keyfile = strndup(loc+8, strcspn(loc+8, ","));
623 goto next;
625 if(!strncmp(loc, "cacertfile=", 11)) {
626 *cacertfile = strndup(loc+11, strcspn(loc+11, ","));
627 goto next;
629 if(!strncmp(loc, "tlshostname=", 9)) {
630 *tlshostname = strndup(loc+9, strcspn(loc+9, ","));
631 goto next;
633 // skip unknown options, with a warning unless they start with a '_'
634 l = strcspn(loc, ",");
635 if(*loc != '_') {
636 char* s = strndup(loc, l);
637 fprintf(stderr, "Warning: unknown option '%s' found in nbdtab file", s);
638 free(s);
640 loc += l;
641 next:
642 if(*loc == ',') {
643 loc++;
645 } while(strcspn(loc, lsep) > 0);
646 retval = true;
647 out:
648 if(data != NULL) {
649 munmap(data, size);
651 if(fd >= 0) {
652 close(fd);
654 return retval;
657 void setsizes(int nbd, u64 size64, int blocksize, u32 flags) {
658 unsigned long size;
659 int read_only = (flags & NBD_FLAG_READ_ONLY) ? 1 : 0;
661 if (size64>>12 > (uint64_t)~0UL)
662 err("Device too large.\n");
663 else {
664 int tmp_blocksize = 4096;
665 if (size64 / (u64)blocksize <= (uint64_t)~0UL)
666 tmp_blocksize = blocksize;
667 if (ioctl(nbd, NBD_SET_BLKSIZE, tmp_blocksize) < 0) {
668 fprintf(stderr, "Failed to set blocksize %d\n",
669 tmp_blocksize);
670 err("Ioctl/1.1a failed: %m\n");
672 size = (unsigned long)(size64 / (u64)tmp_blocksize);
673 if (ioctl(nbd, NBD_SET_SIZE_BLOCKS, size) < 0)
674 err("Ioctl/1.1b failed: %m\n");
675 if (tmp_blocksize != blocksize) {
676 if (ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long)blocksize) < 0) {
677 fprintf(stderr, "Failed to set blocksize %d\n",
678 blocksize);
679 err("Ioctl/1.1c failed: %m\n");
682 fprintf(stderr, "bs=%d, sz=%" PRIu64 " bytes\n", blocksize, (u64)tmp_blocksize * size);
685 ioctl(nbd, NBD_CLEAR_SOCK);
687 /* ignore error as kernel may not support */
688 ioctl(nbd, NBD_SET_FLAGS, (unsigned long) flags);
690 if (ioctl(nbd, BLKROSET, (unsigned long) &read_only) < 0)
691 err("Unable to set read-only attribute for device");
694 void set_timeout(int nbd, int timeout) {
695 if (timeout) {
696 if (ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long)timeout) < 0)
697 err("Ioctl NBD_SET_TIMEOUT failed: %m\n");
698 fprintf(stderr, "timeout=%d\n", timeout);
702 void finish_sock(int sock, int nbd, int swap) {
703 if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) {
704 if (errno == EBUSY)
705 err("Kernel doesn't support multiple connections\n");
706 else
707 err("Ioctl NBD_SET_SOCK failed: %m\n");
710 #ifndef __ANDROID__
711 if (swap)
712 mlockall(MCL_CURRENT | MCL_FUTURE);
713 #endif
716 static int
717 oom_adjust(const char *file, const char *value)
719 int fd, rc;
720 size_t len;
722 fd = open(file, O_WRONLY);
723 if (fd < 0)
724 return -1;
725 len = strlen(value);
726 rc = write(fd, value, len) != (ssize_t) len;
727 close(fd);
728 return rc ? -1 : 0;
731 void usage(char* errmsg, ...) {
732 if(errmsg) {
733 char tmp[256];
734 va_list ap;
735 va_start(ap, errmsg);
736 snprintf(tmp, 256, "ERROR: %s\n\n", errmsg);
737 vfprintf(stderr, tmp, ap);
738 va_end(ap);
739 } else {
740 fprintf(stderr, "nbd-client version %s\n", PACKAGE_VERSION);
742 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");
743 fprintf(stderr, "Or : nbd-client -u (with same arguments as above)\n");
744 fprintf(stderr, "Or : nbd-client nbdX\n");
745 fprintf(stderr, "Or : nbd-client -d nbd_device\n");
746 fprintf(stderr, "Or : nbd-client -c nbd_device\n");
747 fprintf(stderr, "Or : nbd-client -h|--help\n");
748 fprintf(stderr, "Or : nbd-client -l|--list host\n");
749 #if HAVE_GNUTLS && !defined(NOTLS)
750 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");
751 #endif
752 fprintf(stderr, "Default value for blocksize is 1024 (recommended for ethernet)\n");
753 fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */
754 fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n");
755 fprintf(stderr, "blocksizes other than 1024 without patches\n");
756 fprintf(stderr, "Default value for port is 10809. Note that port must always be numeric\n");
759 void disconnect(char* device) {
760 int nbd = open(device, O_RDWR);
762 if (nbd < 0)
763 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
764 printf("disconnect, ");
765 if (ioctl(nbd, NBD_DISCONNECT)<0)
766 err("Ioctl failed: %m\n");
767 printf("sock, ");
768 if (ioctl(nbd, NBD_CLEAR_SOCK)<0)
769 err("Ioctl failed: %m\n");
770 printf("done\n");
773 int main(int argc, char *argv[]) {
774 char* port=NBD_DEFAULT_PORT;
775 int sock, nbd;
776 int blocksize=1024;
777 char *hostname=NULL;
778 char *nbddev=NULL;
779 int swap=0;
780 int cont=0;
781 int timeout=0;
782 int sdp=0;
783 int G_GNUC_UNUSED nofork=0; // if -dNOFORK
784 pid_t main_pid;
785 u64 size64;
786 uint16_t flags = 0;
787 int c;
788 int nonspecial=0;
789 int b_unix=0;
790 char* name="";
791 uint16_t needed_flags=0;
792 uint32_t cflags=NBD_FLAG_C_FIXED_NEWSTYLE;
793 uint32_t opts=0;
794 sigset_t block, old;
795 char *certfile = NULL;
796 char *keyfile = NULL;
797 char *cacertfile = NULL;
798 char *tlshostname = NULL;
799 bool tls = false;
800 struct sigaction sa;
801 int num_connections = 1;
802 struct option long_options[] = {
803 { "block-size", required_argument, NULL, 'b' },
804 { "check", required_argument, NULL, 'c' },
805 { "connections", required_argument, NULL, 'C'},
806 { "disconnect", required_argument, NULL, 'd' },
807 { "help", no_argument, NULL, 'h' },
808 { "list", no_argument, NULL, 'l' },
809 { "name", required_argument, NULL, 'N' },
810 { "nofork", no_argument, NULL, 'n' },
811 { "persist", no_argument, NULL, 'p' },
812 { "sdp", no_argument, NULL, 'S' },
813 { "swap", no_argument, NULL, 's' },
814 { "systemd-mark", no_argument, NULL, 'm' },
815 { "timeout", required_argument, NULL, 't' },
816 { "unix", no_argument, NULL, 'u' },
817 { "certfile", required_argument, NULL, 'F' },
818 { "keyfile", required_argument, NULL, 'K' },
819 { "cacertfile", required_argument, NULL, 'A' },
820 { "tlshostname", required_argument, NULL, 'H' },
821 { "enable-tls", no_argument, NULL, 'x' },
822 { 0, 0, 0, 0 },
824 int i;
826 logging(MY_NAME);
828 #if HAVE_GNUTLS && !defined(NOTLS)
829 tlssession_init();
830 #endif
832 while((c=getopt_long_only(argc, argv, "-b:c:d:hlnN:pSst:uC:K:A:H:x", long_options, NULL))>=0) {
833 switch(c) {
834 case 1:
835 // non-option argument
836 if(strchr(optarg, '=')) {
837 // old-style 'bs=' or 'timeout='
838 // argument
839 fprintf(stderr, "WARNING: old-style command-line argument encountered. This is deprecated.\n");
840 if(!strncmp(optarg, "bs=", 3)) {
841 optarg+=3;
842 goto blocksize;
844 if(!strncmp(optarg, "timeout=", 8)) {
845 optarg+=8;
846 goto timeout;
848 usage("unknown option %s encountered", optarg);
849 exit(EXIT_FAILURE);
851 switch(nonspecial++) {
852 case 0:
853 // host
854 hostname=optarg;
855 break;
856 case 1:
857 // port
858 if(!strtol(optarg, NULL, 0)) {
859 // not parseable as a number, assume it's the device
860 nbddev = optarg;
861 nonspecial++;
862 } else {
863 port = optarg;
865 break;
866 case 2:
867 // device
868 nbddev = optarg;
869 break;
870 default:
871 usage("too many non-option arguments specified");
872 exit(EXIT_FAILURE);
874 break;
875 case 'b':
876 blocksize:
877 blocksize=(int)strtol(optarg, NULL, 0);
878 break;
879 case 'c':
880 return check_conn(optarg, 1);
881 case 'C':
882 num_connections = (int)strtol(optarg, NULL, 0);
883 break;
884 case 'd':
885 disconnect(optarg);
886 exit(EXIT_SUCCESS);
887 case 'h':
888 usage(NULL);
889 exit(EXIT_SUCCESS);
890 case 'l':
891 needed_flags |= NBD_FLAG_FIXED_NEWSTYLE;
892 opts |= NBDC_DO_LIST;
893 nbddev="";
894 break;
895 case 'm':
896 argv[0][0] = '@';
897 break;
898 case 'n':
899 nofork=1;
900 break;
901 case 'N':
902 name=optarg;
903 break;
904 case 'p':
905 cont=1;
906 break;
907 case 's':
908 swap=1;
909 break;
910 case 'S':
911 sdp=1;
912 break;
913 case 't':
914 timeout:
915 timeout=strtol(optarg, NULL, 0);
916 break;
917 case 'u':
918 b_unix = 1;
919 break;
920 #if HAVE_GNUTLS && !defined(NOTLS)
921 case 'x':
922 tls = true;
923 break;
924 case 'F':
925 certfile=strdup(optarg);
926 break;
927 case 'K':
928 keyfile=strdup(optarg);
929 break;
930 case 'A':
931 cacertfile=strdup(optarg);
932 break;
933 case 'H':
934 tlshostname=strdup(optarg);
935 break;
936 #else
937 case 'F':
938 case 'K':
939 case 'H':
940 case 'A':
941 fprintf(stderr, "E: TLS support not compiled in\n");
942 exit(EXIT_FAILURE);
943 #endif
944 default:
945 fprintf(stderr, "E: option eaten by 42 mice\n");
946 exit(EXIT_FAILURE);
950 #ifdef __ANDROID__
951 if (swap)
952 err("swap option unsupported on Android because mlockall is unsupported.");
953 #endif
954 if(hostname) {
955 if((!name || !nbddev) && !(opts & NBDC_DO_LIST)) {
956 if(!strncmp(hostname, "nbd", 3) || !strncmp(hostname, "/dev/nbd", 8)) {
957 if(!get_from_config(hostname, &name, &nbddev, &hostname, &blocksize, &timeout, &cont, &swap, &sdp, &b_unix, &port, &num_connections, &certfile, &keyfile, &cacertfile, &hostname)) {
958 usage("no valid configuration for specified device found", hostname);
959 exit(EXIT_FAILURE);
961 } else {
962 usage("not enough information specified, and argument didn't look like an nbd device");
963 exit(EXIT_FAILURE);
966 } else {
967 usage("no information specified");
968 exit(EXIT_FAILURE);
971 if (keyfile && !certfile)
972 certfile = strdup(keyfile);
974 if (certfile != NULL || keyfile != NULL || cacertfile != NULL || tlshostname != NULL) {
975 tls = true;
978 if (!tlshostname && hostname)
979 tlshostname = strdup(hostname);
981 if(strlen(name)==0 && !(opts & NBDC_DO_LIST)) {
982 printf("Warning: the oldstyle protocol is no longer supported.\nThis method now uses the newstyle protocol with a default export\n");
985 if(!opts & NBDC_DO_LIST) {
986 nbd = open(nbddev, O_RDWR);
987 if (nbd < 0)
988 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
991 for (i = 0; i < num_connections; i++) {
992 if (b_unix)
993 sock = openunix(hostname);
994 else
995 sock = opennet(hostname, port, sdp);
996 if (sock < 0)
997 exit(EXIT_FAILURE);
999 negotiate(&sock, &size64, &flags, name, needed_flags, cflags, opts, certfile, keyfile, cacertfile, tlshostname, tls);
1000 if (i == 0) {
1001 setsizes(nbd, size64, blocksize, flags);
1002 set_timeout(nbd, timeout);
1004 finish_sock(sock, nbd, swap);
1005 if (swap) {
1006 if (keyfile)
1007 fprintf(stderr, "Warning: using swap and TLS is prone to deadlock\n");
1008 /* try linux >= 2.6.36 interface first */
1009 if (oom_adjust("/proc/self/oom_score_adj", "-1000")) {
1010 /* fall back to linux <= 2.6.35 interface */
1011 oom_adjust("/proc/self/oom_adj", "-17");
1016 /* Go daemon */
1018 #ifndef NOFORK
1019 if(!nofork) {
1020 if (daemon(0,0) < 0)
1021 err("Cannot detach from terminal");
1024 memset(&sa, 0, sizeof(sa));
1025 sa.sa_handler = SIG_IGN;
1026 sigaction(SIGCHLD, &sa, NULL);
1027 #endif
1028 /* For child to check its parent */
1029 main_pid = getpid();
1030 do {
1031 #ifndef NOFORK
1033 sigfillset(&block);
1034 sigdelset(&block, SIGKILL);
1035 sigdelset(&block, SIGTERM);
1036 sigdelset(&block, SIGPIPE);
1037 sigprocmask(SIG_SETMASK, &block, &old);
1039 if (!fork()) {
1040 /* Due to a race, the kernel NBD driver cannot
1041 * call for a reread of the partition table
1042 * in the handling of the NBD_DO_IT ioctl().
1043 * Therefore, this is done in the first open()
1044 * of the device. We therefore make sure that
1045 * the device is opened at least once after the
1046 * connection was made. This has to be done in a
1047 * separate process, since the NBD_DO_IT ioctl()
1048 * does not return until the NBD device has
1049 * disconnected.
1051 struct timespec req = {
1052 .tv_sec = 0,
1053 .tv_nsec = 100000000,
1055 while(check_conn(nbddev, 0)) {
1056 if (main_pid != getppid()) {
1057 /* check_conn() will not return 0 when nbd disconnected
1058 * and parent exited during this loop. So the child has to
1059 * explicitly check parent identity and exit if parent
1060 * exited */
1061 exit(0);
1063 nanosleep(&req, NULL);
1065 open(nbddev, O_RDONLY);
1066 exit(0);
1068 #endif
1070 if (ioctl(nbd, NBD_DO_IT) < 0) {
1071 int error = errno;
1072 fprintf(stderr, "nbd,%d: Kernel call returned: %d", main_pid, error);
1073 if(error==EBADR) {
1074 /* The user probably did 'nbd-client -d' on us.
1075 * quit */
1076 cont=0;
1077 } else {
1078 if(cont) {
1079 u64 new_size;
1080 uint16_t new_flags;
1082 close(sock); close(nbd);
1083 for (;;) {
1084 fprintf(stderr, " Reconnecting\n");
1085 if (b_unix)
1086 sock = openunix(hostname);
1087 else
1088 sock = opennet(hostname, port, sdp);
1089 if (sock >= 0)
1090 break;
1091 sleep (1);
1093 nbd = open(nbddev, O_RDWR);
1094 if (nbd < 0)
1095 err("Cannot open NBD: %m");
1096 negotiate(&sock, &new_size, &new_flags, name, needed_flags, cflags, opts, certfile, keyfile, cacertfile, tlshostname, tls);
1097 if (size64 != new_size) {
1098 err("Size of the device changed. Bye");
1100 setsizes(nbd, size64, blocksize,
1101 new_flags);
1103 set_timeout(nbd, timeout);
1104 finish_sock(sock,nbd,swap);
1107 } else {
1108 /* We're on 2.4. It's not clearly defined what exactly
1109 * happened at this point. Probably best to quit, now
1111 fprintf(stderr, "Kernel call returned.");
1112 cont=0;
1114 } while(cont);
1115 printf("sock, ");
1116 ioctl(nbd, NBD_CLEAR_SOCK);
1117 printf("done\n");
1118 return 0;