Fix WRITE_ZEROES/STARTTLS combination
[nbd.git] / nbd-client.c
blob852c8166aec56d0b5f6ffb09eebd3943beeae598
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 <stdio.h>
34 #include <fcntl.h>
35 #include <syslog.h>
36 #include <stdlib.h>
37 #include <sys/mount.h>
38 #include <sys/mman.h>
39 #include <signal.h>
40 #include <errno.h>
41 #include <getopt.h>
42 #include <stdarg.h>
43 #include <stdbool.h>
44 #include <time.h>
46 #include <linux/ioctl.h>
47 #define MY_NAME "nbd_client"
48 #include "cliserv.h"
50 #if HAVE_GNUTLS
51 #include "crypto-gnutls.h"
52 #endif
54 #ifdef WITH_SDP
55 #include <sdp_inet.h>
56 #endif
58 #define NBDC_DO_LIST 1
60 int check_conn(char* devname, int do_print) {
61 char buf[256];
62 char* p;
63 int fd;
64 int len;
66 if( (p=strrchr(devname, '/')) ) {
67 devname=p+1;
69 if((p=strchr(devname, 'p'))) {
70 /* We can't do checks on partitions. */
71 *p='\0';
73 snprintf(buf, 256, "/sys/block/%s/pid", devname);
74 if((fd=open(buf, O_RDONLY))<0) {
75 if(errno==ENOENT) {
76 return 1;
77 } else {
78 return 2;
81 len=read(fd, buf, 256);
82 if(len < 0) {
83 perror("could not read from server");
84 close(fd);
85 return 2;
87 buf[(len < 256) ? len : 255]='\0';
88 if(do_print) printf("%s\n", buf);
89 close(fd);
90 return 0;
93 int opennet(char *name, char* portstr, int sdp) {
94 int sock;
95 struct addrinfo hints;
96 struct addrinfo *ai = NULL;
97 struct addrinfo *rp = NULL;
98 int e;
100 memset(&hints,'\0',sizeof(hints));
101 hints.ai_family = AF_UNSPEC;
102 hints.ai_socktype = SOCK_STREAM;
103 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
104 hints.ai_protocol = IPPROTO_TCP;
106 e = getaddrinfo(name, portstr, &hints, &ai);
108 if(e != 0) {
109 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
110 freeaddrinfo(ai);
111 return -1;
114 if(sdp) {
115 #ifdef WITH_SDP
116 if (ai->ai_family == AF_INET)
117 ai->ai_family = AF_INET_SDP;
118 else (ai->ai_family == AF_INET6)
119 ai->ai_family = AF_INET6_SDP;
120 #else
121 err("Can't do SDP: I was not compiled with SDP support!");
122 #endif
125 for(rp = ai; rp != NULL; rp = rp->ai_next) {
126 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
128 if(sock == -1)
129 continue; /* error */
131 if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
132 break; /* success */
134 close(sock);
137 if (rp == NULL) {
138 err_nonfatal("Socket failed: %m");
139 sock = -1;
140 goto err;
143 setmysockopt(sock);
144 err:
145 freeaddrinfo(ai);
146 return sock;
149 int openunix(const char *path) {
150 int sock;
151 struct sockaddr_un un_addr;
152 memset(&un_addr, 0, sizeof(un_addr));
154 un_addr.sun_family = AF_UNIX;
155 if (strnlen(path, sizeof(un_addr.sun_path)) == sizeof(un_addr.sun_path)) {
156 err_nonfatal("UNIX socket path too long");
157 return -1;
160 strncpy(un_addr.sun_path, path, sizeof(un_addr.sun_path) - 1);
162 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
163 err_nonfatal("SOCKET failed");
164 return -1;
167 if (connect(sock, &un_addr, sizeof(un_addr)) == -1) {
168 err_nonfatal("CONNECT failed");
169 close(sock);
170 return -1;
172 return sock;
175 void ask_list(int sock) {
176 uint32_t opt;
177 uint32_t opt_server;
178 uint32_t len;
179 uint32_t reptype;
180 uint64_t magic;
181 int rlen;
182 const int BUF_SIZE = 1024;
183 char buf[BUF_SIZE];
185 magic = ntohll(opts_magic);
186 if (write(sock, &magic, sizeof(magic)) < 0)
187 err("Failed/2.2: %m");
189 /* Ask for the list */
190 opt = htonl(NBD_OPT_LIST);
191 if(write(sock, &opt, sizeof(opt)) < 0) {
192 err("writing list option failed: %m");
194 /* Send the length (zero) */
195 len = htonl(0);
196 if(write(sock, &len, sizeof(len)) < 0) {
197 err("writing length failed: %m");
199 /* newline, move away from the "Negotiation:" line */
200 printf("\n");
201 do {
202 memset(buf, 0, 1024);
203 if(read(sock, &magic, sizeof(magic)) < 0) {
204 err("Reading magic from server: %m");
206 if(read(sock, &opt_server, sizeof(opt_server)) < 0) {
207 err("Reading option: %m");
209 if(read(sock, &reptype, sizeof(reptype)) <0) {
210 err("Reading reply from server: %m");
212 if(read(sock, &len, sizeof(len)) < 0) {
213 err("Reading length from server: %m");
215 magic=ntohll(magic);
216 len=ntohl(len);
217 reptype=ntohl(reptype);
218 if(magic != rep_magic) {
219 err("Not enough magic from server");
221 if(reptype & NBD_REP_FLAG_ERROR) {
222 switch(reptype) {
223 case NBD_REP_ERR_POLICY:
224 fprintf(stderr, "\nE: listing not allowed by server.\n");
225 break;
226 default:
227 fprintf(stderr, "\nE: unexpected error from server.\n");
228 break;
230 if(len > 0 && len < BUF_SIZE) {
231 if((rlen=read(sock, buf, len)) < 0) {
232 fprintf(stderr, "\nE: could not read error message from server\n");
233 } else {
234 buf[rlen] = '\0';
235 fprintf(stderr, "Server said: %s\n", buf);
238 exit(EXIT_FAILURE);
239 } else {
240 if(len) {
241 if(reptype != NBD_REP_SERVER) {
242 err("Server sent us a reply we don't understand!");
244 if(read(sock, &len, sizeof(len)) < 0) {
245 fprintf(stderr, "\nE: could not read export name length from server\n");
246 exit(EXIT_FAILURE);
248 len=ntohl(len);
249 if (len >= BUF_SIZE) {
250 fprintf(stderr, "\nE: export name on server too long\n");
251 exit(EXIT_FAILURE);
253 if(read(sock, buf, len) < 0) {
254 fprintf(stderr, "\nE: could not read export name from server\n");
255 exit(EXIT_FAILURE);
257 buf[len] = 0;
258 printf("%s\n", buf);
261 } while(reptype != NBD_REP_ACK);
262 opt=htonl(NBD_OPT_ABORT);
263 len=htonl(0);
264 magic=htonll(opts_magic);
265 if (write(sock, &magic, sizeof(magic)) < 0)
266 err("Failed/2.2: %m");
267 if (write(sock, &opt, sizeof(opt)) < 0)
268 err("Failed writing abort");
269 if (write(sock, &len, sizeof(len)) < 0)
270 err("Failed writing length");
273 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) {
274 u64 magic, size64;
275 uint16_t tmp;
276 uint16_t global_flags;
277 char buf[256] = "\0\0\0\0\0\0\0\0\0";
278 uint32_t opt;
279 uint32_t namesize;
280 int sock = *sockp;
282 printf("Negotiation: ");
283 readit(sock, buf, 8);
284 if (strcmp(buf, INIT_PASSWD))
285 err("INIT_PASSWD bad");
286 printf(".");
287 readit(sock, &magic, sizeof(magic));
288 magic = ntohll(magic);
289 if (magic != opts_magic) {
290 if(magic == cliserv_magic) {
291 err("It looks like you're trying to connect to an oldstyle server. This is no longer supported since nbd 3.10.");
294 printf(".");
295 readit(sock, &tmp, sizeof(uint16_t));
296 global_flags = ntohs(tmp);
297 if((needed_flags & global_flags) != needed_flags) {
298 /* There's currently really only one reason why this
299 * check could possibly fail, but we may need to change
300 * this error message in the future... */
301 fprintf(stderr, "\nE: Server does not support listing exports\n");
302 exit(EXIT_FAILURE);
305 if (global_flags & NBD_FLAG_NO_ZEROES) {
306 client_flags |= NBD_FLAG_C_NO_ZEROES;
308 client_flags = htonl(client_flags);
309 if (write(sock, &client_flags, sizeof(client_flags)) < 0)
310 err("Failed/2.1: %m");
312 #if HAVE_GNUTLS
313 /* TLS */
314 if (tls) {
315 int plainfd[2]; // [0] is used by the proxy, [1] is used by NBD
316 tlssession_t *s = NULL;
317 int ret;
318 uint32_t tmp32;
319 uint64_t tmp64;
321 /* magic */
322 tmp64 = htonll(opts_magic);
323 if (write(sock, &tmp64, sizeof(tmp64)) < 0)
324 err( "Could not write magic: %m");
325 /* starttls */
326 tmp32 = htonl(NBD_OPT_STARTTLS);
327 if (write(sock, &tmp32, sizeof(tmp32)) < 0)
328 err("Could not write option: %m");
329 /* length of data */
330 tmp32 = htonl(0);
331 if (write(sock, &tmp32, sizeof(tmp32)) < 0)
332 err("Could not write option length: %m");
334 if (read(sock, &tmp64, sizeof(tmp64)) < 0)
335 err("Could not read cliserv_magic: %m");
336 tmp64 = ntohll(tmp64);
337 if (tmp64 != NBD_OPT_REPLY_MAGIC) {
338 err("reply magic does not match");
340 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
341 err("Could not read option type: %m");
342 tmp32 = ntohl(tmp32);
343 if (tmp32 != NBD_OPT_STARTTLS)
344 err("Reply to wrong option");
345 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
346 err("Could not read option reply type: %m");
347 tmp32 = ntohl(tmp32);
348 if (tmp32 != NBD_REP_ACK) {
349 err("Option reply type != NBD_REP_ACK");
351 if (read(sock, &tmp32, sizeof(tmp32)) < 0) err(
352 "Could not read option data length: %m");
353 tmp32 = ntohl(tmp32);
354 if (tmp32 != 0) {
355 err("Option reply data length != 0");
357 s = tlssession_new(0,
358 keyfile,
359 certfile,
360 cacertfile,
361 tlshostname,
362 !cacertfile || !tlshostname, // insecure flag
363 #ifdef DODBG
364 1, // debug
365 #else
366 0, // debug
367 #endif
368 NULL, // quitfn
369 NULL, // erroutfn
370 NULL // opaque
372 if (!s)
373 err("Cannot establish TLS session");
375 if (socketpair(AF_UNIX, SOCK_STREAM, 0, plainfd) < 0)
376 err("Cannot get socket pair");
378 if (set_nonblocking(plainfd[0], 0) <0 ||
379 set_nonblocking(plainfd[1], 0) <0 ||
380 set_nonblocking(sock, 0) <0) {
381 close(plainfd[0]);
382 close(plainfd[1]);
383 err("Cannot set socket options");
386 ret = fork();
387 if (ret < 0)
388 err("Could not fork");
389 else if (ret == 0) {
390 // we are the child
391 if (daemon(0, 0) < 0) {
392 /* no one will see this */
393 fprintf(stderr, "Can't detach from the terminal");
394 exit(1);
396 signal (SIGPIPE, SIG_IGN);
397 close(plainfd[1]);
398 tlssession_mainloop(sock, plainfd[0], s);
399 close(sock);
400 close(plainfd[0]);
401 exit(0);
403 close(plainfd[0]);
404 close(sock);
405 sock = plainfd[1]; /* use the decrypted FD from now on */
406 *sockp = sock;
408 #else
409 if (keyfile) {
410 err("TLS requested but support not compiled in");
412 #endif
414 if(do_opts & NBDC_DO_LIST) {
415 ask_list(sock);
416 exit(EXIT_SUCCESS);
419 /* Write the export name that we're after */
420 magic = htonll(opts_magic);
421 if (write(sock, &magic, sizeof(magic)) < 0)
422 err("Failed/2.2: %m");
424 opt = ntohl(NBD_OPT_EXPORT_NAME);
425 if (write(sock, &opt, sizeof(opt)) < 0)
426 err("Failed/2.3: %m");
427 namesize = (u32)strlen(name);
428 namesize = ntohl(namesize);
429 if (write(sock, &namesize, sizeof(namesize)) < 0)
430 err("Failed/2.4: %m");
431 if (write(sock, name, strlen(name)) < 0)
432 err("Failed/2.4: %m");
434 readit(sock, &size64, sizeof(size64));
435 size64 = ntohll(size64);
437 if ((size64>>12) > (uint64_t)~0UL) {
438 printf("size = %luMB", (unsigned long)(size64>>20));
439 err("Exported device is too big for me. Get 64-bit machine :-(\n");
440 } else
441 printf("size = %luMB", (unsigned long)(size64>>20));
443 readit(sock, &tmp, sizeof(tmp));
444 *flags = (uint32_t)ntohs(tmp);
446 if (!(global_flags & NBD_FLAG_NO_ZEROES)) {
447 readit(sock, &buf, 124);
449 printf("\n");
451 *rsize64 = size64;
454 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) {
455 int fd = open(SYSCONFDIR "/nbdtab", O_RDONLY);
456 bool retval = false;
457 if(fd < 0) {
458 fprintf(stderr, "while opening %s: ", SYSCONFDIR "/nbdtab");
459 perror("could not open config file");
460 goto out;
462 off_t size = lseek(fd, 0, SEEK_END);
463 lseek(fd, 0, SEEK_SET);
464 void *data = NULL;
465 char *fsep = "\n\t# ";
466 char *lsep = "\n#";
468 if(size < 0) {
469 perror("E: mmap'ing nbdtab");
470 exit(EXIT_FAILURE);
473 data = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED, fd, 0);
474 if(!strncmp(cfgname, "/dev/", 5)) {
475 cfgname += 5;
477 char *loc = strstr((const char*)data, cfgname);
478 if(!loc) {
479 goto out;
481 size_t l = strlen(cfgname) + 6;
482 *dev_ptr = malloc(l);
483 snprintf(*dev_ptr, l, "/dev/%s", cfgname);
485 size_t line_len, field_len, ws_len;
486 #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; }
487 #define MOVE_NEXT line_len -= field_len + ws_len; loc += field_len + ws_len
488 // find length of line
489 line_len = strcspn(loc, lsep);
490 // first field is the device node name, which we already know, so skip it
491 CHECK_LEN;
492 MOVE_NEXT;
493 // next field is the hostname
494 CHECK_LEN;
495 *hostn_ptr = strndup(loc, field_len);
496 MOVE_NEXT;
497 // third field is the export name
498 CHECK_LEN;
499 *name_ptr = strndup(loc, field_len);
500 if(ws_len + field_len > line_len) {
501 // optional last field is not there, so return success
502 retval = true;
503 goto out;
505 MOVE_NEXT;
506 CHECK_LEN;
507 #undef CHECK_LEN
508 #undef MOVE_NEXT
509 // fourth field is the options field, a comma-separated field of options
510 do {
511 if(!strncmp(loc, "conns=", 6)) {
512 *num_conns = (int)strtol(loc+6, &loc, 0);
513 goto next;
515 if(!strncmp(loc, "bs=", 3)) {
516 *bs = (int)strtol(loc+3, &loc, 0);
517 goto next;
519 if(!strncmp(loc, "timeout=", 8)) {
520 *timeout = (int)strtol(loc+8, &loc, 0);
521 goto next;
523 if(!strncmp(loc, "port=", 5)) {
524 *port = strndup(loc+5, strcspn(loc+5, ","));
525 goto next;
527 if(!strncmp(loc, "persist", 7)) {
528 loc += 7;
529 *persist = 1;
530 goto next;
532 if(!strncmp(loc, "swap", 4)) {
533 *swap = 1;
534 loc += 4;
535 goto next;
537 if(!strncmp(loc, "sdp", 3)) {
538 *sdp = 1;
539 loc += 3;
540 goto next;
542 if(!strncmp(loc, "unix", 4)) {
543 *b_unix = 1;
544 loc += 4;
545 goto next;
547 if(!strncmp(loc, "certfile=", 9)) {
548 *certfile = strndup(loc+9, strcspn(loc+9, ","));
549 goto next;
551 if(!strncmp(loc, "keyfile=", 8)) {
552 *keyfile = strndup(loc+8, strcspn(loc+8, ","));
553 goto next;
555 if(!strncmp(loc, "cacertfile=", 11)) {
556 *cacertfile = strndup(loc+11, strcspn(loc+11, ","));
557 goto next;
559 if(!strncmp(loc, "tlshostname=", 9)) {
560 *tlshostname = strndup(loc+9, strcspn(loc+9, ","));
561 goto next;
563 // skip unknown options, with a warning unless they start with a '_'
564 l = strcspn(loc, ",");
565 if(*loc != '_') {
566 char* s = strndup(loc, l);
567 fprintf(stderr, "Warning: unknown option '%s' found in nbdtab file", s);
568 free(s);
570 loc += l;
571 next:
572 if(*loc == ',') {
573 loc++;
575 } while(strcspn(loc, lsep) > 0);
576 retval = true;
577 out:
578 if(data != NULL) {
579 munmap(data, size);
581 if(fd >= 0) {
582 close(fd);
584 return retval;
587 void setsizes(int nbd, u64 size64, int blocksize, u32 flags) {
588 unsigned long size;
589 int read_only = (flags & NBD_FLAG_READ_ONLY) ? 1 : 0;
591 if (size64>>12 > (uint64_t)~0UL)
592 err("Device too large.\n");
593 else {
594 int tmp_blocksize = 4096;
595 if (size64 / (u64)blocksize <= (uint64_t)~0UL)
596 tmp_blocksize = blocksize;
597 if (ioctl(nbd, NBD_SET_BLKSIZE, tmp_blocksize) < 0) {
598 fprintf(stderr, "Failed to set blocksize %d\n",
599 tmp_blocksize);
600 err("Ioctl/1.1a failed: %m\n");
602 size = (unsigned long)(size64 / (u64)tmp_blocksize);
603 if (ioctl(nbd, NBD_SET_SIZE_BLOCKS, size) < 0)
604 err("Ioctl/1.1b failed: %m\n");
605 if (tmp_blocksize != blocksize) {
606 if (ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long)blocksize) < 0) {
607 fprintf(stderr, "Failed to set blocksize %d\n",
608 blocksize);
609 err("Ioctl/1.1c failed: %m\n");
612 fprintf(stderr, "bs=%d, sz=%llu bytes\n", blocksize, (u64)tmp_blocksize * size);
615 ioctl(nbd, NBD_CLEAR_SOCK);
617 /* ignore error as kernel may not support */
618 ioctl(nbd, NBD_SET_FLAGS, (unsigned long) flags);
620 if (ioctl(nbd, BLKROSET, (unsigned long) &read_only) < 0)
621 err("Unable to set read-only attribute for device");
624 void set_timeout(int nbd, int timeout) {
625 if (timeout) {
626 if (ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long)timeout) < 0)
627 err("Ioctl NBD_SET_TIMEOUT failed: %m\n");
628 fprintf(stderr, "timeout=%d\n", timeout);
632 void finish_sock(int sock, int nbd, int swap) {
633 if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) {
634 if (errno == EBUSY)
635 err("Kernel doesn't support multiple connections\n");
636 else
637 err("Ioctl NBD_SET_SOCK failed: %m\n");
640 #ifndef __ANDROID__
641 if (swap)
642 mlockall(MCL_CURRENT | MCL_FUTURE);
643 #endif
646 static int
647 oom_adjust(const char *file, const char *value)
649 int fd, rc;
650 size_t len;
652 fd = open(file, O_WRONLY);
653 if (fd < 0)
654 return -1;
655 len = strlen(value);
656 rc = write(fd, value, len) != (ssize_t) len;
657 close(fd);
658 return rc ? -1 : 0;
661 void usage(char* errmsg, ...) {
662 if(errmsg) {
663 char tmp[256];
664 va_list ap;
665 va_start(ap, errmsg);
666 snprintf(tmp, 256, "ERROR: %s\n\n", errmsg);
667 vfprintf(stderr, tmp, ap);
668 va_end(ap);
669 } else {
670 fprintf(stderr, "nbd-client version %s\n", PACKAGE_VERSION);
672 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");
673 fprintf(stderr, "Or : nbd-client -u (with same arguments as above)\n");
674 fprintf(stderr, "Or : nbd-client nbdX\n");
675 fprintf(stderr, "Or : nbd-client -d nbd_device\n");
676 fprintf(stderr, "Or : nbd-client -c nbd_device\n");
677 fprintf(stderr, "Or : nbd-client -h|--help\n");
678 fprintf(stderr, "Or : nbd-client -l|--list host\n");
679 #if HAVE_GNUTLS
680 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");
681 #endif
682 fprintf(stderr, "Default value for blocksize is 1024 (recommended for ethernet)\n");
683 fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */
684 fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n");
685 fprintf(stderr, "blocksizes other than 1024 without patches\n");
686 fprintf(stderr, "Default value for port is 10809. Note that port must always be numeric\n");
689 void disconnect(char* device) {
690 int nbd = open(device, O_RDWR);
692 if (nbd < 0)
693 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
694 printf("disconnect, ");
695 if (ioctl(nbd, NBD_DISCONNECT)<0)
696 err("Ioctl failed: %m\n");
697 printf("sock, ");
698 if (ioctl(nbd, NBD_CLEAR_SOCK)<0)
699 err("Ioctl failed: %m\n");
700 printf("done\n");
703 int main(int argc, char *argv[]) {
704 char* port=NBD_DEFAULT_PORT;
705 int sock, nbd;
706 int blocksize=1024;
707 char *hostname=NULL;
708 char *nbddev=NULL;
709 int swap=0;
710 int cont=0;
711 int timeout=0;
712 int sdp=0;
713 int G_GNUC_UNUSED nofork=0; // if -dNOFORK
714 pid_t main_pid;
715 u64 size64;
716 uint16_t flags = 0;
717 int c;
718 int nonspecial=0;
719 int b_unix=0;
720 char* name="";
721 uint16_t needed_flags=0;
722 uint32_t cflags=NBD_FLAG_C_FIXED_NEWSTYLE;
723 uint32_t opts=0;
724 sigset_t block, old;
725 char *certfile = NULL;
726 char *keyfile = NULL;
727 char *cacertfile = NULL;
728 char *tlshostname = NULL;
729 bool tls = false;
730 struct sigaction sa;
731 int num_connections = 1;
732 struct option long_options[] = {
733 { "block-size", required_argument, NULL, 'b' },
734 { "check", required_argument, NULL, 'c' },
735 { "connections", required_argument, NULL, 'C'},
736 { "disconnect", required_argument, NULL, 'd' },
737 { "help", no_argument, NULL, 'h' },
738 { "list", no_argument, NULL, 'l' },
739 { "name", required_argument, NULL, 'N' },
740 { "nofork", no_argument, NULL, 'n' },
741 { "persist", no_argument, NULL, 'p' },
742 { "sdp", no_argument, NULL, 'S' },
743 { "swap", no_argument, NULL, 's' },
744 { "systemd-mark", no_argument, NULL, 'm' },
745 { "timeout", required_argument, NULL, 't' },
746 { "unix", no_argument, NULL, 'u' },
747 { "certfile", required_argument, NULL, 'F' },
748 { "keyfile", required_argument, NULL, 'K' },
749 { "cacertfile", required_argument, NULL, 'A' },
750 { "tlshostname", required_argument, NULL, 'H' },
751 { "enable-tls", no_argument, NULL, 'x' },
752 { 0, 0, 0, 0 },
754 int i;
756 logging(MY_NAME);
758 #if HAVE_GNUTLS
759 tlssession_init();
760 #endif
762 while((c=getopt_long_only(argc, argv, "-b:c:d:hlnN:pSst:uC:K:A:H:x", long_options, NULL))>=0) {
763 switch(c) {
764 case 1:
765 // non-option argument
766 if(strchr(optarg, '=')) {
767 // old-style 'bs=' or 'timeout='
768 // argument
769 fprintf(stderr, "WARNING: old-style command-line argument encountered. This is deprecated.\n");
770 if(!strncmp(optarg, "bs=", 3)) {
771 optarg+=3;
772 goto blocksize;
774 if(!strncmp(optarg, "timeout=", 8)) {
775 optarg+=8;
776 goto timeout;
778 usage("unknown option %s encountered", optarg);
779 exit(EXIT_FAILURE);
781 switch(nonspecial++) {
782 case 0:
783 // host
784 hostname=optarg;
785 break;
786 case 1:
787 // port
788 if(!strtol(optarg, NULL, 0)) {
789 // not parseable as a number, assume it's the device
790 nbddev = optarg;
791 nonspecial++;
792 } else {
793 port = optarg;
795 break;
796 case 2:
797 // device
798 nbddev = optarg;
799 break;
800 default:
801 usage("too many non-option arguments specified");
802 exit(EXIT_FAILURE);
804 break;
805 case 'b':
806 blocksize:
807 blocksize=(int)strtol(optarg, NULL, 0);
808 break;
809 case 'c':
810 return check_conn(optarg, 1);
811 case 'C':
812 num_connections = (int)strtol(optarg, NULL, 0);
813 break;
814 case 'd':
815 disconnect(optarg);
816 exit(EXIT_SUCCESS);
817 case 'h':
818 usage(NULL);
819 exit(EXIT_SUCCESS);
820 case 'l':
821 needed_flags |= NBD_FLAG_FIXED_NEWSTYLE;
822 opts |= NBDC_DO_LIST;
823 nbddev="";
824 break;
825 case 'm':
826 argv[0][0] = '@';
827 break;
828 case 'n':
829 nofork=1;
830 break;
831 case 'N':
832 name=optarg;
833 break;
834 case 'p':
835 cont=1;
836 break;
837 case 's':
838 swap=1;
839 break;
840 case 'S':
841 sdp=1;
842 break;
843 case 't':
844 timeout:
845 timeout=strtol(optarg, NULL, 0);
846 break;
847 case 'u':
848 b_unix = 1;
849 break;
850 #if HAVE_GNUTLS
851 case 'x':
852 tls = true;
853 break;
854 case 'F':
855 certfile=strdup(optarg);
856 break;
857 case 'K':
858 keyfile=strdup(optarg);
859 break;
860 case 'A':
861 cacertfile=strdup(optarg);
862 break;
863 case 'H':
864 tlshostname=strdup(optarg);
865 break;
866 #else
867 case 'F':
868 case 'K':
869 case 'H':
870 case 'A':
871 fprintf(stderr, "E: TLS support not compiled in\n");
872 exit(EXIT_FAILURE);
873 #endif
874 default:
875 fprintf(stderr, "E: option eaten by 42 mice\n");
876 exit(EXIT_FAILURE);
880 #ifdef __ANDROID__
881 if (swap)
882 err("swap option unsupported on Android because mlockall is unsupported.");
883 #endif
884 if(hostname) {
885 if((!name || !nbddev) && !(opts & NBDC_DO_LIST)) {
886 if(!strncmp(hostname, "nbd", 3) || !strncmp(hostname, "/dev/nbd", 8)) {
887 if(!get_from_config(hostname, &name, &nbddev, &hostname, &blocksize, &timeout, &cont, &swap, &sdp, &b_unix, &port, &num_connections, &certfile, &keyfile, &cacertfile, &hostname)) {
888 usage("no valid configuration for specified device found", hostname);
889 exit(EXIT_FAILURE);
891 } else {
892 usage("not enough information specified, and argument didn't look like an nbd device");
893 exit(EXIT_FAILURE);
896 } else {
897 usage("no information specified");
898 exit(EXIT_FAILURE);
901 if (keyfile && !certfile)
902 certfile = strdup(keyfile);
904 if (certfile != NULL || keyfile != NULL || cacertfile != NULL || tlshostname != NULL) {
905 tls = true;
908 if (!tlshostname && hostname)
909 tlshostname = strdup(hostname);
911 if(strlen(name)==0 && !(opts & NBDC_DO_LIST)) {
912 printf("Warning: the oldstyle protocol is no longer supported.\nThis method now uses the newstyle protocol with a default export\n");
915 if(!opts & NBDC_DO_LIST) {
916 nbd = open(nbddev, O_RDWR);
917 if (nbd < 0)
918 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
921 for (i = 0; i < num_connections; i++) {
922 if (b_unix)
923 sock = openunix(hostname);
924 else
925 sock = opennet(hostname, port, sdp);
926 if (sock < 0)
927 exit(EXIT_FAILURE);
929 negotiate(&sock, &size64, &flags, name, needed_flags, cflags, opts, certfile, keyfile, cacertfile, tlshostname, tls);
930 if (i == 0) {
931 setsizes(nbd, size64, blocksize, flags);
932 set_timeout(nbd, timeout);
934 finish_sock(sock, nbd, swap);
935 if (swap) {
936 if (keyfile)
937 fprintf(stderr, "Warning: using swap and TLS is prone to deadlock\n");
938 /* try linux >= 2.6.36 interface first */
939 if (oom_adjust("/proc/self/oom_score_adj", "-1000")) {
940 /* fall back to linux <= 2.6.35 interface */
941 oom_adjust("/proc/self/oom_adj", "-17");
946 /* Go daemon */
948 #ifndef NOFORK
949 if(!nofork) {
950 if (daemon(0,0) < 0)
951 err("Cannot detach from terminal");
954 memset(&sa, 0, sizeof(sa));
955 sa.sa_handler = SIG_IGN;
956 sigaction(SIGCHLD, &sa, NULL);
957 #endif
958 /* For child to check its parent */
959 main_pid = getpid();
960 do {
961 #ifndef NOFORK
963 sigfillset(&block);
964 sigdelset(&block, SIGKILL);
965 sigdelset(&block, SIGTERM);
966 sigdelset(&block, SIGPIPE);
967 sigprocmask(SIG_SETMASK, &block, &old);
969 if (!fork()) {
970 /* Due to a race, the kernel NBD driver cannot
971 * call for a reread of the partition table
972 * in the handling of the NBD_DO_IT ioctl().
973 * Therefore, this is done in the first open()
974 * of the device. We therefore make sure that
975 * the device is opened at least once after the
976 * connection was made. This has to be done in a
977 * separate process, since the NBD_DO_IT ioctl()
978 * does not return until the NBD device has
979 * disconnected.
981 struct timespec req = {
982 .tv_sec = 0,
983 .tv_nsec = 100000000,
985 while(check_conn(nbddev, 0)) {
986 if (main_pid != getppid()) {
987 /* check_conn() will not return 0 when nbd disconnected
988 * and parent exited during this loop. So the child has to
989 * explicitly check parent identity and exit if parent
990 * exited */
991 exit(0);
993 nanosleep(&req, NULL);
995 open(nbddev, O_RDONLY);
996 exit(0);
998 #endif
1000 if (ioctl(nbd, NBD_DO_IT) < 0) {
1001 int error = errno;
1002 fprintf(stderr, "nbd,%d: Kernel call returned: %d", main_pid, error);
1003 if(error==EBADR) {
1004 /* The user probably did 'nbd-client -d' on us.
1005 * quit */
1006 cont=0;
1007 } else {
1008 if(cont) {
1009 u64 new_size;
1010 uint16_t new_flags;
1012 close(sock); close(nbd);
1013 for (;;) {
1014 fprintf(stderr, " Reconnecting\n");
1015 if (b_unix)
1016 sock = openunix(hostname);
1017 else
1018 sock = opennet(hostname, port, sdp);
1019 if (sock >= 0)
1020 break;
1021 sleep (1);
1023 nbd = open(nbddev, O_RDWR);
1024 if (nbd < 0)
1025 err("Cannot open NBD: %m");
1026 negotiate(&sock, &new_size, &new_flags, name, needed_flags, cflags, opts, certfile, keyfile, cacertfile, tlshostname, tls);
1027 if (size64 != new_size) {
1028 err("Size of the device changed. Bye");
1030 setsizes(nbd, size64, blocksize,
1031 new_flags);
1033 set_timeout(nbd, timeout);
1034 finish_sock(sock,nbd,swap);
1037 } else {
1038 /* We're on 2.4. It's not clearly defined what exactly
1039 * happened at this point. Probably best to quit, now
1041 fprintf(stderr, "Kernel call returned.");
1042 cont=0;
1044 } while(cont);
1045 printf("sock, ");
1046 ioctl(nbd, NBD_CLEAR_SOCK);
1047 printf("done\n");
1048 return 0;