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>
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
27 #include <sys/types.h>
29 #include <netinet/tcp.h>
30 #include <netinet/in.h>
32 #include "netdb-compat.h"
38 #include <sys/mount.h>
47 #include <linux/ioctl.h>
48 #define MY_NAME "nbd_client"
51 #if HAVE_GNUTLS && !defined(NOTLS)
52 #include "crypto-gnutls.h"
59 #define NBDC_DO_LIST 1
61 int check_conn(char* devname
, int do_print
) {
67 if( (p
=strrchr(devname
, '/')) ) {
70 if((p
=strchr(devname
, 'p'))) {
71 /* We can't do checks on partitions. */
74 snprintf(buf
, 256, "/sys/block/%s/pid", devname
);
75 if((fd
=open(buf
, O_RDONLY
))<0) {
82 len
=read(fd
, buf
, 256);
84 perror("could not read from server");
88 buf
[(len
< 256) ? len
: 255]='\0';
89 if(do_print
) printf("%s\n", buf
);
94 int opennet(char *name
, char* portstr
, int sdp
) {
96 struct addrinfo hints
;
97 struct addrinfo
*ai
= NULL
;
98 struct addrinfo
*rp
= NULL
;
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
);
110 fprintf(stderr
, "getaddrinfo failed: %s\n", gai_strerror(e
));
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
;
122 err("Can't do SDP: I was not compiled with SDP support!");
126 for(rp
= ai
; rp
!= NULL
; rp
= rp
->ai_next
) {
127 sock
= socket(rp
->ai_family
, rp
->ai_socktype
, rp
->ai_protocol
);
130 continue; /* error */
132 if(connect(sock
, rp
->ai_addr
, rp
->ai_addrlen
) != -1)
139 err_nonfatal("Socket failed: %m");
150 int openunix(const char *path
) {
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");
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");
168 if (connect(sock
, &un_addr
, sizeof(un_addr
)) == -1) {
169 err_nonfatal("CONNECT failed");
176 void send_request(int sock
, uint32_t opt
, ssize_t datasize
, void* data
) {
181 } __attribute__((packed
)) header
= {
187 datasize
= strlen((char*)data
);
188 header
.datasize
= htonl(datasize
);
190 writeit(sock
, &header
, sizeof(header
));
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
));
205 writeit(sock
, reqs
, n_reqs
* sizeof(uint16_t));
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
);
228 if (retval
->datasize
> 0) {
229 retval
= realloc(retval
, sizeof(struct reply
) + retval
->datasize
);
230 readit(sock
, &(retval
->data
), retval
->datasize
);
235 void ask_list(int sock
) {
243 const int BUF_SIZE
= 1024;
246 send_request(sock
, NBD_OPT_LIST
, 0, NULL
);
247 /* newline, move away from the "Negotiation:" line */
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");
265 reptype
=ntohl(reptype
);
266 if(magic
!= rep_magic
) {
267 err("Not enough magic from server");
269 if(reptype
& NBD_REP_FLAG_ERROR
) {
271 case NBD_REP_ERR_POLICY
:
272 fprintf(stderr
, "\nE: listing not allowed by server.\n");
275 fprintf(stderr
, "\nE: unexpected error from server.\n");
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");
283 fprintf(stderr
, "Server said: %s\n", buf
);
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");
297 if (lenn
>= BUF_SIZE
) {
298 fprintf(stderr
, "\nE: export name on server too long\n");
301 if(read(sock
, buf
, lenn
) < 0) {
302 fprintf(stderr
, "\nE: could not read export name from server\n");
310 if(read(sock
, buf
, len
) < 0) {
311 fprintf(stderr
, "\nE: could not read export description from server\n");
315 printf(": %s\n", buf
);
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
);
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");
336 printf("size = %luMB", (unsigned long)(*size
>>20));
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
) {
344 uint16_t global_flags
;
345 char buf
[256] = "\0\0\0\0\0\0\0\0\0";
350 printf("Negotiation: ");
351 readit(sock
, buf
, 8);
352 if (strcmp(buf
, INIT_PASSWD
))
353 err("INIT_PASSWD bad");
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.");
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");
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)
383 int plainfd
[2]; // [0] is used by the proxy, [1] is used by NBD
384 tlssession_t
*s
= NULL
;
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
);
412 err("Option reply data length != 0");
414 s
= tlssession_new(0,
419 !cacertfile
|| !tlshostname
, // insecure flag
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) {
440 err("Cannot set socket options");
445 err("Could not fork");
448 if (daemon(0, 0) < 0) {
449 /* no one will see this */
450 fprintf(stderr
, "Can't detach from the terminal");
453 signal (SIGPIPE
, SIG_IGN
);
455 tlssession_mainloop(sock
, plainfd
[0], s
);
462 sock
= plainfd
[1]; /* use the decrypted FD from now on */
467 err("TLS requested but support not compiled in");
471 if(do_opts
& NBDC_DO_LIST
) {
476 send_info_request(sock
, NBD_OPT_GO
, 0, NULL
, name
);
478 struct reply
*rep
= NULL
;
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
) {
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);
497 err("Unknown error in reply to NBD_OPT_GO; cannot continue");
502 switch(rep
->reply_type
) {
504 memcpy(&info_type
, rep
->data
, 2);
505 info_type
= htons(info_type
);
507 case NBD_INFO_EXPORT
:
508 parse_sizes(rep
->data
+ 2, rsize64
, flags
);
511 // ignore these, don't need them
518 err_nonfatal("Unknown reply to NBD_OPT_GO received");
520 } while(rep
->reply_type
!= NBD_REP_ACK
);
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
);
528 fprintf(stderr
, "while opening %s: ", SYSCONFDIR
"/nbdtab");
529 perror("could not open config file");
532 off_t size
= lseek(fd
, 0, SEEK_END
);
533 lseek(fd
, 0, SEEK_SET
);
535 char *fsep
= "\n\t# ";
539 perror("E: mmap'ing nbdtab");
543 data
= mmap(NULL
, (size_t)size
, PROT_READ
, MAP_SHARED
, fd
, 0);
544 if(!strncmp(cfgname
, "/dev/", 5)) {
547 char *loc
= strstr((const char*)data
, cfgname
);
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
563 // next field is the hostname
565 *hostn_ptr
= strndup(loc
, field_len
);
567 // third field is the export name
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
579 // fourth field is the options field, a comma-separated field of options
581 if(!strncmp(loc
, "conns=", 6)) {
582 *num_conns
= (int)strtol(loc
+6, &loc
, 0);
585 if(!strncmp(loc
, "bs=", 3)) {
586 *bs
= (int)strtol(loc
+3, &loc
, 0);
589 if(!strncmp(loc
, "timeout=", 8)) {
590 *timeout
= (int)strtol(loc
+8, &loc
, 0);
593 if(!strncmp(loc
, "port=", 5)) {
594 *port
= strndup(loc
+5, strcspn(loc
+5, ","));
597 if(!strncmp(loc
, "persist", 7)) {
602 if(!strncmp(loc
, "swap", 4)) {
607 if(!strncmp(loc
, "sdp", 3)) {
612 if(!strncmp(loc
, "unix", 4)) {
617 if(!strncmp(loc
, "certfile=", 9)) {
618 *certfile
= strndup(loc
+9, strcspn(loc
+9, ","));
621 if(!strncmp(loc
, "keyfile=", 8)) {
622 *keyfile
= strndup(loc
+8, strcspn(loc
+8, ","));
625 if(!strncmp(loc
, "cacertfile=", 11)) {
626 *cacertfile
= strndup(loc
+11, strcspn(loc
+11, ","));
629 if(!strncmp(loc
, "tlshostname=", 9)) {
630 *tlshostname
= strndup(loc
+9, strcspn(loc
+9, ","));
633 // skip unknown options, with a warning unless they start with a '_'
634 l
= strcspn(loc
, ",");
636 char* s
= strndup(loc
, l
);
637 fprintf(stderr
, "Warning: unknown option '%s' found in nbdtab file", s
);
645 } while(strcspn(loc
, lsep
) > 0);
657 void setsizes(int nbd
, u64 size64
, int blocksize
, u32 flags
) {
659 int read_only
= (flags
& NBD_FLAG_READ_ONLY
) ? 1 : 0;
661 if (size64
>>12 > (uint64_t)~0UL)
662 err("Device too large.\n");
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",
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",
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
) {
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) {
705 err("Kernel doesn't support multiple connections\n");
707 err("Ioctl NBD_SET_SOCK failed: %m\n");
712 mlockall(MCL_CURRENT
| MCL_FUTURE
);
717 oom_adjust(const char *file
, const char *value
)
722 fd
= open(file
, O_WRONLY
);
726 rc
= write(fd
, value
, len
) != (ssize_t
) len
;
731 void usage(char* errmsg
, ...) {
735 va_start(ap
, errmsg
);
736 snprintf(tmp
, 256, "ERROR: %s\n\n", errmsg
);
737 vfprintf(stderr
, tmp
, ap
);
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");
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
);
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");
768 if (ioctl(nbd
, NBD_CLEAR_SOCK
)<0)
769 err("Ioctl failed: %m\n");
773 int main(int argc
, char *argv
[]) {
774 char* port
=NBD_DEFAULT_PORT
;
783 int G_GNUC_UNUSED nofork
=0; // if -dNOFORK
791 uint16_t needed_flags
=0;
792 uint32_t cflags
=NBD_FLAG_C_FIXED_NEWSTYLE
;
795 char *certfile
= NULL
;
796 char *keyfile
= NULL
;
797 char *cacertfile
= NULL
;
798 char *tlshostname
= NULL
;
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' },
828 #if HAVE_GNUTLS && !defined(NOTLS)
832 while((c
=getopt_long_only(argc
, argv
, "-b:c:d:hlnN:pSst:uC:K:A:H:x", long_options
, NULL
))>=0) {
835 // non-option argument
836 if(strchr(optarg
, '=')) {
837 // old-style 'bs=' or 'timeout='
839 fprintf(stderr
, "WARNING: old-style command-line argument encountered. This is deprecated.\n");
840 if(!strncmp(optarg
, "bs=", 3)) {
844 if(!strncmp(optarg
, "timeout=", 8)) {
848 usage("unknown option %s encountered", optarg
);
851 switch(nonspecial
++) {
858 if(!strtol(optarg
, NULL
, 0)) {
859 // not parseable as a number, assume it's the device
871 usage("too many non-option arguments specified");
877 blocksize
=(int)strtol(optarg
, NULL
, 0);
880 return check_conn(optarg
, 1);
882 num_connections
= (int)strtol(optarg
, NULL
, 0);
891 needed_flags
|= NBD_FLAG_FIXED_NEWSTYLE
;
892 opts
|= NBDC_DO_LIST
;
915 timeout
=strtol(optarg
, NULL
, 0);
920 #if HAVE_GNUTLS && !defined(NOTLS)
925 certfile
=strdup(optarg
);
928 keyfile
=strdup(optarg
);
931 cacertfile
=strdup(optarg
);
934 tlshostname
=strdup(optarg
);
941 fprintf(stderr
, "E: TLS support not compiled in\n");
945 fprintf(stderr
, "E: option eaten by 42 mice\n");
952 err("swap option unsupported on Android because mlockall is unsupported.");
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
);
962 usage("not enough information specified, and argument didn't look like an nbd device");
967 usage("no information specified");
971 if (keyfile
&& !certfile
)
972 certfile
= strdup(keyfile
);
974 if (certfile
!= NULL
|| keyfile
!= NULL
|| cacertfile
!= NULL
|| tlshostname
!= NULL
) {
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
);
988 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
991 for (i
= 0; i
< num_connections
; i
++) {
993 sock
= openunix(hostname
);
995 sock
= opennet(hostname
, port
, sdp
);
999 negotiate(&sock
, &size64
, &flags
, name
, needed_flags
, cflags
, opts
, certfile
, keyfile
, cacertfile
, tlshostname
, tls
);
1001 setsizes(nbd
, size64
, blocksize
, flags
);
1002 set_timeout(nbd
, timeout
);
1004 finish_sock(sock
, nbd
, swap
);
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");
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
);
1028 /* For child to check its parent */
1029 main_pid
= getpid();
1034 sigdelset(&block
, SIGKILL
);
1035 sigdelset(&block
, SIGTERM
);
1036 sigdelset(&block
, SIGPIPE
);
1037 sigprocmask(SIG_SETMASK
, &block
, &old
);
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
1051 struct timespec req
= {
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
1063 nanosleep(&req
, NULL
);
1065 open(nbddev
, O_RDONLY
);
1070 if (ioctl(nbd
, NBD_DO_IT
) < 0) {
1072 fprintf(stderr
, "nbd,%d: Kernel call returned: %d", main_pid
, error
);
1074 /* The user probably did 'nbd-client -d' on us.
1082 close(sock
); close(nbd
);
1084 fprintf(stderr
, " Reconnecting\n");
1086 sock
= openunix(hostname
);
1088 sock
= opennet(hostname
, port
, sdp
);
1093 nbd
= open(nbddev
, O_RDWR
);
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
,
1103 set_timeout(nbd
, timeout
);
1104 finish_sock(sock
,nbd
,swap
);
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.");
1116 ioctl(nbd
, NBD_CLEAR_SOCK
);