Network Block Device  @PACKAGE_VERSION@
nbd-client.c
Go to the documentation of this file.
1 /*
2  * Open connection for network block device
3  *
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>
7  *
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>
19  */
20 
21 #include "config.h"
22 #include "lfs.h"
23 
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>
45 
46 #include <linux/ioctl.h>
47 #define MY_NAME "nbd_client"
48 #include "cliserv.h"
49 
50 #ifdef WITH_SDP
51 #include <sdp_inet.h>
52 #endif
53 
54 #define NBDC_DO_LIST 1
55 
56 int check_conn(char* devname, int do_print) {
57  char buf[256];
58  char* p;
59  int fd;
60  int len;
61 
62  if( (p=strrchr(devname, '/')) ) {
63  devname=p+1;
64  }
65  if((p=strchr(devname, 'p'))) {
66  /* We can't do checks on partitions. */
67  *p='\0';
68  }
69  snprintf(buf, 256, "/sys/block/%s/pid", devname);
70  if((fd=open(buf, O_RDONLY))<0) {
71  if(errno==ENOENT) {
72  return 1;
73  } else {
74  return 2;
75  }
76  }
77  len=read(fd, buf, 256);
78  if(len < 0) {
79  perror("could not read from server");
80  return 2;
81  }
82  buf[(len < 256) ? len : 255]='\0';
83  if(do_print) printf("%s\n", buf);
84  close(fd);
85  return 0;
86 }
87 
88 int opennet(char *name, char* portstr, int sdp) {
89  int sock;
90  struct addrinfo hints;
91  struct addrinfo *ai = NULL;
92  struct addrinfo *rp = NULL;
93  int e;
94 
95  memset(&hints,'\0',sizeof(hints));
96  hints.ai_family = AF_UNSPEC;
97  hints.ai_socktype = SOCK_STREAM;
98  hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
99  hints.ai_protocol = IPPROTO_TCP;
100 
101  e = getaddrinfo(name, portstr, &hints, &ai);
102 
103  if(e != 0) {
104  fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
105  freeaddrinfo(ai);
106  return -1;
107  }
108 
109  if(sdp) {
110 #ifdef WITH_SDP
111  if (ai->ai_family == AF_INET)
112  ai->ai_family = AF_INET_SDP;
113  else (ai->ai_family == AF_INET6)
114  ai->ai_family = AF_INET6_SDP;
115 #else
116  err("Can't do SDP: I was not compiled with SDP support!");
117 #endif
118  }
119 
120  for(rp = ai; rp != NULL; rp = rp->ai_next) {
121  sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
122 
123  if(sock == -1)
124  continue; /* error */
125 
126  if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
127  break; /* success */
128 
129  close(sock);
130  }
131 
132  if (rp == NULL) {
133  err_nonfatal("Socket failed: %m");
134  sock = -1;
135  goto err;
136  }
137 
138  setmysockopt(sock);
139 err:
140  freeaddrinfo(ai);
141  return sock;
142 }
143 
144 int openunix(const char *path) {
145  int sock;
146  struct sockaddr_un un_addr;
147  memset(&un_addr, 0, sizeof(un_addr));
148 
149  un_addr.sun_family = AF_UNIX;
150  if (strnlen(path, sizeof(un_addr.sun_path)) == sizeof(un_addr.sun_path)) {
151  err_nonfatal("UNIX socket path too long");
152  return -1;
153  }
154 
155  strncpy(un_addr.sun_path, path, sizeof(un_addr.sun_path) - 1);
156 
157  if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
158  err_nonfatal("SOCKET failed");
159  return -1;
160  };
161 
162  if (connect(sock, &un_addr, sizeof(un_addr)) == -1) {
163  err_nonfatal("CONNECT failed");
164  close(sock);
165  return -1;
166  }
167  return sock;
168 }
169 
170 void ask_list(int sock) {
171  uint32_t opt;
172  uint32_t opt_server;
173  uint32_t len;
174  uint32_t reptype;
175  uint64_t magic;
176  int rlen;
177  const int BUF_SIZE = 1024;
178  char buf[BUF_SIZE];
179 
180  magic = ntohll(opts_magic);
181  if (write(sock, &magic, sizeof(magic)) < 0)
182  err("Failed/2.2: %m");
183 
184  /* Ask for the list */
185  opt = htonl(NBD_OPT_LIST);
186  if(write(sock, &opt, sizeof(opt)) < 0) {
187  err("writing list option failed: %m");
188  }
189  /* Send the length (zero) */
190  len = htonl(0);
191  if(write(sock, &len, sizeof(len)) < 0) {
192  err("writing length failed: %m");
193  }
194  /* newline, move away from the "Negotiation:" line */
195  printf("\n");
196  do {
197  memset(buf, 0, 1024);
198  if(read(sock, &magic, sizeof(magic)) < 0) {
199  err("Reading magic from server: %m");
200  }
201  if(read(sock, &opt_server, sizeof(opt_server)) < 0) {
202  err("Reading option: %m");
203  }
204  if(read(sock, &reptype, sizeof(reptype)) <0) {
205  err("Reading reply from server: %m");
206  }
207  if(read(sock, &len, sizeof(len)) < 0) {
208  err("Reading length from server: %m");
209  }
210  magic=ntohll(magic);
211  len=ntohl(len);
212  reptype=ntohl(reptype);
213  if(magic != rep_magic) {
214  err("Not enough magic from server");
215  }
216  if(reptype & NBD_REP_FLAG_ERROR) {
217  switch(reptype) {
218  case NBD_REP_ERR_POLICY:
219  fprintf(stderr, "\nE: listing not allowed by server.\n");
220  break;
221  default:
222  fprintf(stderr, "\nE: unexpected error from server.\n");
223  break;
224  }
225  if(len > 0 && len < BUF_SIZE) {
226  if((rlen=read(sock, buf, len)) < 0) {
227  fprintf(stderr, "\nE: could not read error message from server\n");
228  } else {
229  buf[rlen] = '\0';
230  fprintf(stderr, "Server said: %s\n", buf);
231  }
232  }
233  exit(EXIT_FAILURE);
234  } else {
235  if(len) {
236  if(reptype != NBD_REP_SERVER) {
237  err("Server sent us a reply we don't understand!");
238  }
239  if(read(sock, &len, sizeof(len)) < 0) {
240  fprintf(stderr, "\nE: could not read export name length from server\n");
241  exit(EXIT_FAILURE);
242  }
243  len=ntohl(len);
244  if (len >= BUF_SIZE) {
245  fprintf(stderr, "\nE: export name on server too long\n");
246  exit(EXIT_FAILURE);
247  }
248  if(read(sock, buf, len) < 0) {
249  fprintf(stderr, "\nE: could not read export name from server\n");
250  exit(EXIT_FAILURE);
251  }
252  buf[len] = 0;
253  printf("%s\n", buf);
254  }
255  }
256  } while(reptype != NBD_REP_ACK);
257  opt=htonl(NBD_OPT_ABORT);
258  len=htonl(0);
259  magic=htonll(opts_magic);
260  if (write(sock, &magic, sizeof(magic)) < 0)
261  err("Failed/2.2: %m");
262  if (write(sock, &opt, sizeof(opt)) < 0)
263  err("Failed writing abort");
264  if (write(sock, &len, sizeof(len)) < 0)
265  err("Failed writing length");
266 }
267 
268 void negotiate(int sock, u64 *rsize64, uint16_t *flags, char* name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts) {
269  u64 magic, size64;
270  uint16_t tmp;
271  uint16_t global_flags;
272  char buf[256] = "\0\0\0\0\0\0\0\0\0";
273  uint32_t opt;
274  uint32_t namesize;
275 
276  printf("Negotiation: ");
277  readit(sock, buf, 8);
278  if (strcmp(buf, INIT_PASSWD))
279  err("INIT_PASSWD bad");
280  printf(".");
281  readit(sock, &magic, sizeof(magic));
282  magic = ntohll(magic);
283  if (magic != opts_magic) {
284  if(magic == cliserv_magic) {
285  err("It looks like you're trying to connect to an oldstyle server. This is no longer supported since nbd 3.10.");
286  }
287  }
288  printf(".");
289  readit(sock, &tmp, sizeof(uint16_t));
290  global_flags = ntohs(tmp);
291  if((needed_flags & global_flags) != needed_flags) {
292  /* There's currently really only one reason why this
293  * check could possibly fail, but we may need to change
294  * this error message in the future... */
295  fprintf(stderr, "\nE: Server does not support listing exports\n");
296  exit(EXIT_FAILURE);
297  }
298 
299  if (global_flags & NBD_FLAG_NO_ZEROES) {
300  client_flags |= NBD_FLAG_C_NO_ZEROES;
301  }
302  client_flags = htonl(client_flags);
303  if (write(sock, &client_flags, sizeof(client_flags)) < 0)
304  err("Failed/2.1: %m");
305 
306  if(do_opts & NBDC_DO_LIST) {
307  ask_list(sock);
308  exit(EXIT_SUCCESS);
309  }
310 
311  /* Write the export name that we're after */
312  magic = htonll(opts_magic);
313  if (write(sock, &magic, sizeof(magic)) < 0)
314  err("Failed/2.2: %m");
315 
316  opt = ntohl(NBD_OPT_EXPORT_NAME);
317  if (write(sock, &opt, sizeof(opt)) < 0)
318  err("Failed/2.3: %m");
319  namesize = (u32)strlen(name);
320  namesize = ntohl(namesize);
321  if (write(sock, &namesize, sizeof(namesize)) < 0)
322  err("Failed/2.4: %m");
323  if (write(sock, name, strlen(name)) < 0)
324  err("Failed/2.4: %m");
325 
326  readit(sock, &size64, sizeof(size64));
327  size64 = ntohll(size64);
328 
329  if ((size64>>12) > (uint64_t)~0UL) {
330  printf("size = %luMB", (unsigned long)(size64>>20));
331  err("Exported device is too big for me. Get 64-bit machine :-(\n");
332  } else
333  printf("size = %luMB", (unsigned long)(size64>>20));
334 
335  readit(sock, &tmp, sizeof(tmp));
336  *flags = (uint32_t)ntohs(tmp);
337 
338  if (!(global_flags & NBD_FLAG_NO_ZEROES)) {
339  readit(sock, &buf, 124);
340  }
341  printf("\n");
342 
343  *rsize64 = size64;
344 }
345 
346 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) {
347  int fd = open(SYSCONFDIR "/nbdtab", O_RDONLY);
348  bool retval = false;
349  if(fd < 0) {
350  fprintf(stderr, "while opening %s: ", SYSCONFDIR "/nbdtab");
351  perror("could not open config file");
352  goto out;
353  }
354  off_t size = lseek(fd, 0, SEEK_END);
355  lseek(fd, 0, SEEK_SET);
356  void *data = NULL;
357  char *fsep = "\n\t# ";
358  char *lsep = "\n#";
359 
360  if(size < 0) {
361  perror("E: mmap'ing nbdtab");
362  exit(EXIT_FAILURE);
363  }
364 
365  data = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED, fd, 0);
366  char *loc = strstr((const char*)data, cfgname);
367  if(!loc) {
368  goto out;
369  }
370  size_t l = strlen(cfgname) + 6;
371  *dev_ptr = malloc(l);
372  snprintf(*dev_ptr, l, "/dev/%s", cfgname);
373 
374  size_t line_len, field_len, ws_len;
375 #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; }
376 #define MOVE_NEXT line_len -= field_len + ws_len; loc += field_len + ws_len
377  // find length of line
378  line_len = strcspn(loc, lsep);
379  // first field is the device node name, which we already know, so skip it
380  CHECK_LEN;
381  MOVE_NEXT;
382  // next field is the hostname
383  CHECK_LEN;
384  *hostn_ptr = strndup(loc, field_len);
385  MOVE_NEXT;
386  // third field is the export name
387  CHECK_LEN;
388  *name_ptr = strndup(loc, field_len);
389  if(ws_len + field_len > line_len) {
390  // optional last field is not there, so return success
391  retval = true;
392  goto out;
393  }
394  MOVE_NEXT;
395  CHECK_LEN;
396 #undef CHECK_LEN
397 #undef MOVE_NEXT
398  // fourth field is the options field, a comma-separated field of options
399  do {
400  if(!strncmp(loc, "bs=", 3)) {
401  *bs = (int)strtol(loc+3, &loc, 0);
402  goto next;
403  }
404  if(!strncmp(loc, "timeout=", 8)) {
405  *timeout = (int)strtol(loc+8, &loc, 0);
406  goto next;
407  }
408  if(!strncmp(loc, "port=", 5)) {
409  *port = strndup(loc+5, strcspn(loc+5, ","));
410  goto next;
411  }
412  if(!strncmp(loc, "persist", 7)) {
413  loc += 7;
414  *persist = 1;
415  goto next;
416  }
417  if(!strncmp(loc, "swap", 4)) {
418  *swap = 1;
419  loc += 4;
420  goto next;
421  }
422  if(!strncmp(loc, "sdp", 3)) {
423  *sdp = 1;
424  loc += 3;
425  goto next;
426  }
427  if(!strncmp(loc, "unix", 4)) {
428  *b_unix = 1;
429  loc += 4;
430  goto next;
431  }
432  // skip unknown options, with a warning unless they start with a '_'
433  l = strcspn(loc, ",");
434  if(*loc != '_') {
435  char* s = strndup(loc, l);
436  fprintf(stderr, "Warning: unknown option '%s' found in nbdtab file", s);
437  free(s);
438  }
439  loc += l;
440 next:
441  if(*loc == ',') {
442  loc++;
443  }
444  } while(strcspn(loc, lsep) > 0);
445  retval = true;
446 out:
447  if(data != NULL) {
448  munmap(data, size);
449  }
450  if(fd >= 0) {
451  close(fd);
452  }
453  return retval;
454 }
455 
456 void setsizes(int nbd, u64 size64, int blocksize, u32 flags) {
457  unsigned long size;
458  int read_only = (flags & NBD_FLAG_READ_ONLY) ? 1 : 0;
459 
460  if (size64>>12 > (uint64_t)~0UL)
461  err("Device too large.\n");
462  else {
463  if (ioctl(nbd, NBD_SET_BLKSIZE, 4096UL) < 0)
464  err("Ioctl/1.1a failed: %m\n");
465  size = (unsigned long)(size64>>12);
466  if (ioctl(nbd, NBD_SET_SIZE_BLOCKS, size) < 0)
467  err("Ioctl/1.1b failed: %m\n");
468  if (ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long)blocksize) < 0)
469  err("Ioctl/1.1c failed: %m\n");
470  fprintf(stderr, "bs=%d, sz=%llu bytes\n", blocksize, 4096ULL*size);
471  }
472 
473  ioctl(nbd, NBD_CLEAR_SOCK);
474 
475  /* ignore error as kernel may not support */
476  ioctl(nbd, NBD_SET_FLAGS, (unsigned long) flags);
477 
478  if (ioctl(nbd, BLKROSET, (unsigned long) &read_only) < 0)
479  err("Unable to set read-only attribute for device");
480 }
481 
482 void set_timeout(int nbd, int timeout) {
483  if (timeout) {
484  if (ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long)timeout) < 0)
485  err("Ioctl NBD_SET_TIMEOUT failed: %m\n");
486  fprintf(stderr, "timeout=%d\n", timeout);
487  }
488 }
489 
490 void finish_sock(int sock, int nbd, int swap) {
491  if (ioctl(nbd, NBD_SET_SOCK, sock) < 0)
492  err("Ioctl NBD_SET_SOCK failed: %m\n");
493 
494 #ifndef __ANDROID__
495  if (swap)
496  mlockall(MCL_CURRENT | MCL_FUTURE);
497 #endif
498 }
499 
500 static int
501 oom_adjust(const char *file, const char *value)
502 {
503  int fd, rc;
504  size_t len;
505 
506  fd = open(file, O_WRONLY);
507  if (fd < 0)
508  return -1;
509  len = strlen(value);
510  rc = write(fd, value, len) != (ssize_t) len;
511  close(fd);
512  return rc ? -1 : 0;
513 }
514 
515 void usage(char* errmsg, ...) {
516  if(errmsg) {
517  char tmp[256];
518  va_list ap;
519  va_start(ap, errmsg);
520  snprintf(tmp, 256, "ERROR: %s\n\n", errmsg);
521  vfprintf(stderr, tmp, ap);
522  va_end(ap);
523  } else {
524  fprintf(stderr, "nbd-client version %s\n", PACKAGE_VERSION);
525  }
526  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");
527  fprintf(stderr, "Or : nbd-client -u (with same arguments as above)\n");
528  fprintf(stderr, "Or : nbd-client nbdX\n");
529  fprintf(stderr, "Or : nbd-client -d nbd_device\n");
530  fprintf(stderr, "Or : nbd-client -c nbd_device\n");
531  fprintf(stderr, "Or : nbd-client -h|--help\n");
532  fprintf(stderr, "Or : nbd-client -l|--list host\n");
533  fprintf(stderr, "Default value for blocksize is 1024 (recommended for ethernet)\n");
534  fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */
535  fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n");
536  fprintf(stderr, "blocksizes other than 1024 without patches\n");
537  fprintf(stderr, "Default value for port is 10809. Note that port must always be numeric\n");
538 }
539 
540 void disconnect(char* device) {
541  int nbd = open(device, O_RDWR);
542 
543  if (nbd < 0)
544  err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
545  printf("disconnect, ");
546  if (ioctl(nbd, NBD_DISCONNECT)<0)
547  err("Ioctl failed: %m\n");
548  printf("sock, ");
549  if (ioctl(nbd, NBD_CLEAR_SOCK)<0)
550  err("Ioctl failed: %m\n");
551  printf("done\n");
552 }
553 
554 int main(int argc, char *argv[]) {
555  char* port=NBD_DEFAULT_PORT;
556  int sock, nbd;
557  int blocksize=1024;
558  char *hostname=NULL;
559  char *nbddev=NULL;
560  int swap=0;
561  int cont=0;
562  int timeout=0;
563  int sdp=0;
564  int G_GNUC_UNUSED nofork=0; // if -dNOFORK
565  u64 size64;
566  uint16_t flags = 0;
567  int c;
568  int nonspecial=0;
569  int b_unix=0;
570  char* name="";
571  uint16_t needed_flags=0;
572  uint32_t cflags=NBD_FLAG_C_FIXED_NEWSTYLE;
573  uint32_t opts=0;
574  sigset_t block, old;
575  struct sigaction sa;
576  struct option long_options[] = {
577  { "block-size", required_argument, NULL, 'b' },
578  { "check", required_argument, NULL, 'c' },
579  { "disconnect", required_argument, NULL, 'd' },
580  { "help", no_argument, NULL, 'h' },
581  { "list", no_argument, NULL, 'l' },
582  { "name", required_argument, NULL, 'N' },
583  { "nofork", no_argument, NULL, 'n' },
584  { "persist", no_argument, NULL, 'p' },
585  { "sdp", no_argument, NULL, 'S' },
586  { "swap", no_argument, NULL, 's' },
587  { "systemd-mark", no_argument, NULL, 'm' },
588  { "timeout", required_argument, NULL, 't' },
589  { "unix", no_argument, NULL, 'u' },
590  { 0, 0, 0, 0 },
591  };
592 
593  logging(MY_NAME);
594 
595  while((c=getopt_long_only(argc, argv, "-b:c:d:hlnN:pSst:u", long_options, NULL))>=0) {
596  switch(c) {
597  case 1:
598  // non-option argument
599  if(strchr(optarg, '=')) {
600  // old-style 'bs=' or 'timeout='
601  // argument
602  fprintf(stderr, "WARNING: old-style command-line argument encountered. This is deprecated.\n");
603  if(!strncmp(optarg, "bs=", 3)) {
604  optarg+=3;
605  goto blocksize;
606  }
607  if(!strncmp(optarg, "timeout=", 8)) {
608  optarg+=8;
609  goto timeout;
610  }
611  usage("unknown option %s encountered", optarg);
612  exit(EXIT_FAILURE);
613  }
614  switch(nonspecial++) {
615  case 0:
616  // host
617  hostname=optarg;
618  break;
619  case 1:
620  // port
621  if(!strtol(optarg, NULL, 0)) {
622  // not parseable as a number, assume it's the device
623  nbddev = optarg;
624  nonspecial++;
625  } else {
626  port = optarg;
627  }
628  break;
629  case 2:
630  // device
631  nbddev = optarg;
632  break;
633  default:
634  usage("too many non-option arguments specified");
635  exit(EXIT_FAILURE);
636  }
637  break;
638  case 'b':
639  blocksize:
640  blocksize=(int)strtol(optarg, NULL, 0);
641  break;
642  case 'c':
643  return check_conn(optarg, 1);
644  case 'd':
645  disconnect(optarg);
646  exit(EXIT_SUCCESS);
647  case 'h':
648  usage(NULL);
649  exit(EXIT_SUCCESS);
650  case 'l':
651  needed_flags |= NBD_FLAG_FIXED_NEWSTYLE;
652  opts |= NBDC_DO_LIST;
653  nbddev="";
654  break;
655  case 'm':
656  argv[0][0] = '@';
657  break;
658  case 'n':
659  nofork=1;
660  break;
661  case 'N':
662  name=optarg;
663  break;
664  case 'p':
665  cont=1;
666  break;
667  case 's':
668  swap=1;
669  break;
670  case 'S':
671  sdp=1;
672  break;
673  case 't':
674  timeout:
675  timeout=strtol(optarg, NULL, 0);
676  break;
677  case 'u':
678  b_unix = 1;
679  break;
680  default:
681  fprintf(stderr, "E: option eaten by 42 mice\n");
682  exit(EXIT_FAILURE);
683  }
684  }
685 
686 #ifdef __ANDROID__
687  if (swap)
688  err("swap option unsupported on Android because mlockall is unsupported.");
689 #endif
690  if(hostname) {
691  if((!name || !nbddev) && !(opts & NBDC_DO_LIST)) {
692  if(!strncmp(hostname, "nbd", 3) || !strncmp(hostname, "/dev/nbd", 8)) {
693  if(!get_from_config(hostname, &name, &nbddev, &hostname, &blocksize, &timeout, &cont, &swap, &sdp, &b_unix, &port)) {
694  usage("no valid configuration for specified device found", hostname);
695  exit(EXIT_FAILURE);
696  }
697  } else {
698  usage("not enough information specified, and argument didn't look like an nbd device");
699  exit(EXIT_FAILURE);
700  }
701  }
702  } else {
703  usage("no information specified");
704  exit(EXIT_FAILURE);
705  }
706 
707  if(strlen(name)==0 && !(opts & NBDC_DO_LIST)) {
708  printf("Warning: the oldstyle protocol is no longer supported.\nThis method now uses the newstyle protocol with a default export\n");
709  }
710 
711  if (b_unix)
712  sock = openunix(hostname);
713  else
714  sock = opennet(hostname, port, sdp);
715  if (sock < 0)
716  exit(EXIT_FAILURE);
717 
718  negotiate(sock, &size64, &flags, name, needed_flags, cflags, opts);
719 
720  nbd = open(nbddev, O_RDWR);
721  if (nbd < 0)
722  err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
723 
724  setsizes(nbd, size64, blocksize, flags);
725  set_timeout(nbd, timeout);
726  finish_sock(sock, nbd, swap);
727  if (swap) {
728  /* try linux >= 2.6.36 interface first */
729  if (oom_adjust("/proc/self/oom_score_adj", "-1000")) {
730  /* fall back to linux <= 2.6.35 interface */
731  oom_adjust("/proc/self/oom_adj", "-17");
732  }
733  }
734 
735  /* Go daemon */
736 
737 #ifndef NOFORK
738  if(!nofork) {
739  if (daemon(0,0) < 0)
740  err("Cannot detach from terminal");
741  }
742 
743  memset(&sa, 0, sizeof(sa));
744  sa.sa_handler = SIG_IGN;
745  sigaction(SIGCHLD, &sa, NULL);
746 #endif
747  do {
748 #ifndef NOFORK
749 
750  sigfillset(&block);
751  sigdelset(&block, SIGKILL);
752  sigdelset(&block, SIGTERM);
753  sigdelset(&block, SIGPIPE);
754  sigprocmask(SIG_SETMASK, &block, &old);
755 
756  if (!fork()) {
757  /* Due to a race, the kernel NBD driver cannot
758  * call for a reread of the partition table
759  * in the handling of the NBD_DO_IT ioctl().
760  * Therefore, this is done in the first open()
761  * of the device. We therefore make sure that
762  * the device is opened at least once after the
763  * connection was made. This has to be done in a
764  * separate process, since the NBD_DO_IT ioctl()
765  * does not return until the NBD device has
766  * disconnected.
767  */
768  struct timespec req = {
769  .tv_sec = 0,
770  .tv_nsec = 100000000,
771  };
772  while(check_conn(nbddev, 0)) {
773  nanosleep(&req, NULL);
774  }
775  open(nbddev, O_RDONLY);
776  exit(0);
777  }
778 #endif
779 
780  if (ioctl(nbd, NBD_DO_IT) < 0) {
781  int error = errno;
782  fprintf(stderr, "nbd,%d: Kernel call returned: %d", getpid(), error);
783  if(error==EBADR) {
784  /* The user probably did 'nbd-client -d' on us.
785  * quit */
786  cont=0;
787  } else {
788  if(cont) {
789  u64 new_size;
790  uint16_t new_flags;
791 
792  close(sock); close(nbd);
793  for (;;) {
794  fprintf(stderr, " Reconnecting\n");
795  if (b_unix)
796  sock = openunix(hostname);
797  else
798  sock = opennet(hostname, port, sdp);
799  if (sock >= 0)
800  break;
801  sleep (1);
802  }
803  nbd = open(nbddev, O_RDWR);
804  if (nbd < 0)
805  err("Cannot open NBD: %m");
806  negotiate(sock, &new_size, &new_flags, name, needed_flags, cflags, opts);
807  if (size64 != new_size) {
808  err("Size of the device changed. Bye");
809  }
810  setsizes(nbd, size64, blocksize,
811  new_flags);
812 
813  set_timeout(nbd, timeout);
814  finish_sock(sock,nbd,swap);
815  }
816  }
817  } else {
818  /* We're on 2.4. It's not clearly defined what exactly
819  * happened at this point. Probably best to quit, now
820  */
821  fprintf(stderr, "Kernel call returned.");
822  cont=0;
823  }
824  } while(cont);
825  printf("sock, ");
826  ioctl(nbd, NBD_CLEAR_SOCK);
827  printf("done\n");
828  return 0;
829 }
void setsizes(int nbd, u64 size64, int blocksize, u32 flags)
Definition: nbd-client.c:456
void disconnect(char *device)
Definition: nbd-client.c:540
#define NBD_REP_FLAG_ERROR
Definition: cliserv.h:102
#define NBD_OPT_LIST
Definition: cliserv.h:97
void negotiate(int sock, u64 *rsize64, uint16_t *flags, char *name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts)
Definition: nbd-client.c:268
void err(const char *s)
Definition: cliserv.c:59
#define NBD_CLEAR_SOCK
Definition: nbd.h:24
#define NBD_FLAG_C_NO_ZEROES
Definition: cliserv.h:113
#define NBD_FLAG_NO_ZEROES
Definition: cliserv.h:110
#define MY_NAME
Definition: nbd-client.c:47
#define SYSCONFDIR
Default position of the config file.
Definition: nbd-server.c:134
uint32_t len
Definition: nbd.h:41
#define NBD_SET_SOCK
Definition: nbd.h:20
void finish_sock(int sock, int nbd, int swap)
Definition: nbd-client.c:490
#define NBD_REP_ERR_POLICY
Definition: cliserv.h:104
#define NBD_SET_SIZE_BLOCKS
Definition: nbd.h:27
void usage(char *errmsg,...)
Definition: nbd-client.c:515
#define NBD_OPT_EXPORT_NAME
Definition: cliserv.h:95
void setmysockopt(int sock)
Definition: cliserv.c:15
#define NBD_REP_ACK
Definition: cliserv.h:100
void err_nonfatal(const char *s)
Definition: cliserv.c:33
const u64 cliserv_magic
Definition: cliserv.c:11
#define NBD_OPT_ABORT
Definition: cliserv.h:96
#define NBDC_DO_LIST
Definition: nbd-client.c:54
#define AI_NUMERICSERV
Definition: netdb-compat.h:21
#define MOVE_NEXT
#define NBD_DISCONNECT
Definition: nbd.h:28
uint32_t magic
Definition: nbd.h:37
#define NBD_SET_TIMEOUT
Definition: nbd.h:29
const u64 rep_magic
Definition: cliserv.c:13
void readit(int f, void *buf, size_t len)
Read data from a file descriptor into a buffer.
Definition: cliserv.c:95
int check_conn(char *devname, int do_print)
Definition: nbd-client.c:56
#define NBD_FLAG_C_FIXED_NEWSTYLE
Definition: cliserv.h:112
const u64 opts_magic
Definition: cliserv.c:12
void ask_list(int sock)
Definition: nbd-client.c:170
#define NBD_FLAG_READ_ONLY
Definition: nbd.h:45
uint64_t ntohll(uint64_t a)
Definition: cliserv.c:78
#define G_GNUC_UNUSED
Definition: cliserv.h:63
#define NBD_SET_FLAGS
Definition: nbd.h:30
void set_timeout(int nbd, int timeout)
Definition: nbd-client.c:482
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)
Definition: nbd-client.c:346
#define NBD_SET_BLKSIZE
Definition: nbd.h:21
int openunix(const char *path)
Definition: nbd-client.c:144
int main(int argc, char *argv[])
Definition: nbd-client.c:554
#define htonll
Definition: cliserv.h:86
static int oom_adjust(const char *file, const char *value)
Definition: nbd-client.c:501
#define NBD_REP_SERVER
Definition: cliserv.h:101
#define NBD_DEFAULT_PORT
Definition: cliserv.h:91
#define CHECK_LEN
#define PACKAGE_VERSION
Definition: config.h:184
int opennet(char *name, char *portstr, int sdp)
Definition: nbd-client.c:88
#define NBD_FLAG_FIXED_NEWSTYLE
Definition: cliserv.h:109
#define INIT_PASSWD
Definition: cliserv.h:71
#define NBD_DO_IT
Definition: nbd.h:23
void logging(const char *name)
Definition: cliserv.c:64