24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <sys/types.h>
28 #include <netinet/tcp.h>
29 #include <netinet/in.h>
35 #include <sys/mount.h>
41 #include <linux/ioctl.h>
42 #define MY_NAME "nbd_client"
49 #define NBDC_DO_LIST 1
57 if( (p=strrchr(devname,
'/')) ) {
60 if((p=strchr(devname,
'p'))) {
64 snprintf(buf, 256,
"/sys/block/%s/pid", devname);
65 if((fd=open(buf, O_RDONLY))<0) {
72 len=read(fd, buf, 256);
74 if(do_print) printf(
"%s\n", buf);
79 int opennet(
char *name,
char* portstr,
int sdp) {
81 struct addrinfo hints;
82 struct addrinfo *ai = NULL;
83 struct addrinfo *rp = NULL;
86 memset(&hints,
'\0',
sizeof(hints));
87 hints.ai_family = AF_UNSPEC;
88 hints.ai_socktype = SOCK_STREAM;
89 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
90 hints.ai_protocol = IPPROTO_TCP;
92 e = getaddrinfo(name, portstr, &hints, &ai);
95 fprintf(stderr,
"getaddrinfo failed: %s\n", gai_strerror(e));
102 if (ai->ai_family == AF_INET)
103 ai->ai_family = AF_INET_SDP;
104 else (ai->ai_family == AF_INET6)
105 ai->ai_family = AF_INET6_SDP;
107 err(
"Can't do SDP: I was not compiled with SDP support!");
111 for(rp = ai; rp != NULL; rp = rp->ai_next) {
112 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
117 if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
122 err(
"Socket failed: %m");
139 if (write(sock, &magic,
sizeof(magic)) < 0)
140 err(
"Failed/2.2: %m");
144 if(write(sock, &opt,
sizeof(opt)) < 0) {
145 err(
"writing list option failed: %m");
149 if(write(sock, &len,
sizeof(len)) < 0) {
150 err(
"writing length failed: %m");
155 memset(buf, 0, 1024);
156 if(read(sock, &magic,
sizeof(magic)) < 0) {
157 err(
"Reading magic from server: %m");
159 if(read(sock, &opt_server,
sizeof(opt_server)) < 0) {
160 err(
"Reading option: %m");
162 if(read(sock, &reptype,
sizeof(reptype)) <0) {
163 err(
"Reading reply from server: %m");
165 if(read(sock, &len,
sizeof(len)) < 0) {
166 err(
"Reading length from server: %m");
170 reptype=ntohl(reptype);
172 err(
"Not enough magic from server");
177 fprintf(stderr,
"\nE: listing not allowed by server.\n");
180 fprintf(stderr,
"\nE: unexpected error from server.\n");
184 if(read(sock, buf, len) < 0) {
185 fprintf(stderr,
"\nE: could not read error message from server\n");
187 fprintf(stderr,
"Server said: %s\n", buf);
193 err(
"Server sent us a reply we don't understand!");
195 if(read(sock, &len,
sizeof(len)) < 0) {
196 fprintf(stderr,
"\nE: could not read export name length from server\n");
200 if(read(sock, buf, len) < 0) {
201 fprintf(stderr,
"\nE: could not read export name from server\n");
211 if (write(sock, &magic,
sizeof(magic)) < 0)
212 err(
"Failed/2.2: %m");
213 if (write(sock, &opt,
sizeof(opt)) < 0)
214 err(
"Failed writing abort");
215 if (write(sock, &len,
sizeof(len)) < 0)
216 err(
"Failed writing length");
219 void negotiate(
int sock, u64 *rsize64, u32 *flags,
char* name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts) {
222 char buf[256] =
"\0\0\0\0\0\0\0\0\0";
224 printf(
"Negotiation: ");
225 if (read(sock, buf, 8) < 0)
228 err(
"Server closed connection");
230 err(
"INIT_PASSWD bad");
232 if (read(sock, &magic,
sizeof(magic)) < 0)
240 err(
"Not enough opts_magic");
242 if(read(sock, &tmp,
sizeof(uint16_t)) < 0) {
243 err(
"Failed reading flags: %m");
245 *flags = ((u32)ntohs(tmp));
246 if((needed_flags & *flags) != needed_flags) {
250 fprintf(stderr,
"\nE: Server does not support listing exports\n");
254 client_flags = htonl(client_flags);
255 if (write(sock, &client_flags,
sizeof(client_flags)) < 0)
256 err(
"Failed/2.1: %m");
265 if (write(sock, &magic,
sizeof(magic)) < 0)
266 err(
"Failed/2.2: %m");
269 if (write(sock, &opt,
sizeof(opt)) < 0)
270 err(
"Failed/2.3: %m");
271 namesize = (u32)strlen(name);
272 namesize = ntohl(namesize);
273 if (write(sock, &namesize,
sizeof(namesize)) < 0)
274 err(
"Failed/2.4: %m");
275 if (write(sock, name, strlen(name)) < 0)
276 err(
"Failed/2.4: %m");
279 err(
"Not enough cliserv_magic");
283 if (read(sock, &size64,
sizeof(size64)) < 0)
284 err(
"Failed/3: %m\n");
287 #ifdef NBD_SET_SIZE_BLOCKS
288 if ((size64>>12) > (uint64_t)~0UL) {
289 printf(
"size = %luMB", (
unsigned long)(size64>>20));
290 err(
"Exported device is too big for me. Get 64-bit machine :-(\n");
292 printf(
"size = %luMB", (
unsigned long)(size64>>20));
294 if (size64 > (~0UL >> 1)) {
295 printf(
"size = %luKB", (
unsigned long)(size64>>10));
296 err(
"Exported device is too big. Get 64-bit machine or newer kernel :-(\n");
298 printf(
"size = %lu", (
unsigned long)(size64));
302 if (read(sock, flags,
sizeof(*flags)) < 0)
303 err(
"Failed/4: %m\n");
304 *flags = ntohl(*flags);
306 if(read(sock, &tmp,
sizeof(tmp)) < 0)
307 err(
"Failed/4: %m\n");
308 *flags |= (uint32_t)ntohs(tmp);
311 if (read(sock, &buf, 124) < 0)
312 err(
"Failed/5: %m\n");
318 void setsizes(
int nbd, u64 size64,
int blocksize, u32 flags) {
322 #ifdef NBD_SET_SIZE_BLOCKS
323 if (size64>>12 > (uint64_t)~0UL)
324 err(
"Device too large.\n");
327 err(
"Ioctl/1.1a failed: %m\n");
328 size = (
unsigned long)(size64>>12);
330 err(
"Ioctl/1.1b failed: %m\n");
332 err(
"Ioctl/1.1c failed: %m\n");
333 fprintf(stderr,
"bs=%d, sz=%llu bytes\n", blocksize, 4096ULL*size);
336 if (size64 > (~0UL >> 1)) {
337 err(
"Device too large.\n");
339 size = (
unsigned long)size64;
341 err(
"Ioctl NBD_SET_SIZE failed: %m\n");
350 if (ioctl(nbd, BLKROSET, (
unsigned long) &read_only) < 0)
351 err(
"Unable to set read-only attribute for device");
356 #ifdef NBD_SET_TIMEOUT
358 err(
"Ioctl NBD_SET_TIMEOUT failed: %m\n");
359 fprintf(stderr,
"timeout=%d\n", timeout);
361 err(
"Ioctl NBD_SET_TIMEOUT cannot be called when compiled on a system that does not support it\n");
368 err(
"Ioctl NBD_SET_SOCK failed: %m\n");
371 mlockall(MCL_CURRENT | MCL_FUTURE);
378 va_start(ap, errmsg);
379 snprintf(tmp, 256,
"ERROR: %s\n\n", errmsg);
380 vfprintf(stderr, tmp, ap);
385 fprintf(stderr,
"Usage: nbd-client host port nbd_device [-block-size|-b block size] [-timeout|-t timeout] [-swap|-s] [-sdp|-S] [-persist|-p] [-nofork|-n]\n");
386 fprintf(stderr,
"Or : nbd-client -name|-N name host [port] nbd_device [-block-size|-b block size] [-timeout|-t timeout] [-swap|-s] [-sdp|-S] [-persist|-p] [-nofork|-n]\n");
387 fprintf(stderr,
"Or : nbd-client -d nbd_device\n");
388 fprintf(stderr,
"Or : nbd-client -c nbd_device\n");
389 fprintf(stderr,
"Or : nbd-client -h|--help\n");
390 fprintf(stderr,
"Or : nbd-client -l|--list host\n");
391 fprintf(stderr,
"Default value for blocksize is 1024 (recommended for ethernet)\n");
392 fprintf(stderr,
"Allowed values for blocksize are 512,1024,2048,4096\n");
393 fprintf(stderr,
"Note, that kernel 2.4.2 and older ones do not work correctly with\n");
394 fprintf(stderr,
"blocksizes other than 1024 without patches\n");
395 fprintf(stderr,
"Default value for port with -N is 10809. Note that port must always be numeric\n");
399 int nbd = open(device, O_RDWR);
402 err(
"Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
403 printf(
"Disconnecting: que, ");
405 err(
"Ioctl failed: %m\n");
406 printf(
"disconnect, ");
407 #ifdef NBD_DISCONNECT
409 err(
"Ioctl failed: %m\n");
412 fprintf(stderr,
"Can't disconnect: I was not compiled with disconnect support!\n" );
416 err(
"Ioctl failed: %m\n");
420 int main(
int argc,
char *argv[]) {
436 uint32_t needed_flags;
439 struct option long_options[] = {
440 {
"block-size", required_argument, NULL,
'b' },
441 {
"check", required_argument, NULL,
'c' },
442 {
"disconnect", required_argument, NULL,
'd' },
443 {
"help", no_argument, NULL,
'h' },
444 {
"list", no_argument, NULL,
'l' },
445 {
"name", required_argument, NULL,
'N' },
446 {
"nofork", no_argument, NULL,
'n' },
447 {
"persist", no_argument, NULL,
'p' },
448 {
"sdp", no_argument, NULL,
'S' },
449 {
"swap", no_argument, NULL,
's' },
450 {
"timeout", required_argument, NULL,
't' },
456 while((c=getopt_long_only(argc, argv,
"-b:c:d:hlnN:pSst:", long_options, NULL))>=0) {
460 if(strchr(optarg,
'=')) {
463 fprintf(stderr,
"WARNING: old-style command-line argument encountered. This is deprecated.\n");
464 if(!strncmp(optarg,
"bs=", 3)) {
468 if(!strncmp(optarg,
"timeout=", 8)) {
472 usage(
"unknown option %s encountered", optarg);
475 switch(nonspecial++) {
482 if(!strtol(optarg, NULL, 0)) {
495 usage(
"too many non-option arguments specified");
501 blocksize=(int)strtol(optarg, NULL, 0);
539 timeout=strtol(optarg, NULL, 0);
542 fprintf(stderr,
"E: option eaten by 42 mice\n");
547 if((!port && !name) || !hostname || !nbddev) {
548 usage(
"not enough information specified");
552 sock =
opennet(hostname, port, sdp);
554 negotiate(sock, &size64, &flags, name, needed_flags, cflags, opts);
556 nbd = open(nbddev, O_RDWR);
558 err(
"Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
560 setsizes(nbd, size64, blocksize, flags);
569 err(
"Cannot detach from terminal");
589 open(nbddev, O_RDONLY);
596 fprintf(stderr,
"nbd,%d: Kernel call returned: %d", getpid(), error);
606 fprintf(stderr,
" Reconnecting\n");
607 close(sock); close(nbd);
608 sock =
opennet(hostname, port, sdp);
609 nbd = open(nbddev, O_RDWR);
610 negotiate(sock, &new_size, &new_flags, name, needed_flags, cflags, opts);
611 if (size64 != new_size) {
612 err(
"Size of the device changed. Bye");
625 fprintf(stderr,
"Kernel call returned.");
629 printf(
"Closing: que, ");