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>
36 #include <sys/mount.h>
43 #include <linux/ioctl.h>
44 #define MY_NAME "nbd_client"
51 #define NBDC_DO_LIST 1
59 if( (p=strrchr(devname,
'/')) ) {
62 if((p=strchr(devname,
'p'))) {
66 snprintf(buf, 256,
"/sys/block/%s/pid", devname);
67 if((fd=open(buf, O_RDONLY))<0) {
74 len=read(fd, buf, 256);
76 if(do_print) printf(
"%s\n", buf);
81 int opennet(
char *name,
char* portstr,
int sdp) {
83 struct addrinfo hints;
84 struct addrinfo *ai = NULL;
85 struct addrinfo *rp = NULL;
88 memset(&hints,
'\0',
sizeof(hints));
89 hints.ai_family = AF_UNSPEC;
90 hints.ai_socktype = SOCK_STREAM;
92 hints.ai_protocol = IPPROTO_TCP;
94 e = getaddrinfo(name, portstr, &hints, &ai);
97 fprintf(stderr,
"getaddrinfo failed: %s\n", gai_strerror(e));
104 if (ai->ai_family == AF_INET)
105 ai->ai_family = AF_INET_SDP;
106 else (ai->ai_family == AF_INET6)
107 ai->ai_family = AF_INET6_SDP;
109 err(
"Can't do SDP: I was not compiled with SDP support!");
113 for(rp = ai; rp != NULL; rp = rp->ai_next) {
114 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
119 if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
143 if (write(sock, &magic,
sizeof(magic)) < 0)
144 err(
"Failed/2.2: %m");
148 if(write(sock, &opt,
sizeof(opt)) < 0) {
149 err(
"writing list option failed: %m");
153 if(write(sock, &len,
sizeof(len)) < 0) {
154 err(
"writing length failed: %m");
159 memset(buf, 0, 1024);
160 if(read(sock, &magic,
sizeof(magic)) < 0) {
161 err(
"Reading magic from server: %m");
163 if(read(sock, &opt_server,
sizeof(opt_server)) < 0) {
164 err(
"Reading option: %m");
166 if(read(sock, &reptype,
sizeof(reptype)) <0) {
167 err(
"Reading reply from server: %m");
169 if(read(sock, &len,
sizeof(len)) < 0) {
170 err(
"Reading length from server: %m");
174 reptype=ntohl(reptype);
176 err(
"Not enough magic from server");
181 fprintf(stderr,
"\nE: listing not allowed by server.\n");
184 fprintf(stderr,
"\nE: unexpected error from server.\n");
188 if(read(sock, buf, len) < 0) {
189 fprintf(stderr,
"\nE: could not read error message from server\n");
191 fprintf(stderr,
"Server said: %s\n", buf);
197 err(
"Server sent us a reply we don't understand!");
199 if(read(sock, &len,
sizeof(len)) < 0) {
200 fprintf(stderr,
"\nE: could not read export name length from server\n");
204 if(read(sock, buf, len) < 0) {
205 fprintf(stderr,
"\nE: could not read export name from server\n");
215 if (write(sock, &magic,
sizeof(magic)) < 0)
216 err(
"Failed/2.2: %m");
217 if (write(sock, &opt,
sizeof(opt)) < 0)
218 err(
"Failed writing abort");
219 if (write(sock, &len,
sizeof(len)) < 0)
220 err(
"Failed writing length");
223 void negotiate(
int sock, u64 *rsize64, u32 *flags,
char* name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts) {
226 char buf[256] =
"\0\0\0\0\0\0\0\0\0";
228 printf(
"Negotiation: ");
229 if (read(sock, buf, 8) < 0)
232 err(
"Server closed connection");
234 err(
"INIT_PASSWD bad");
236 if (read(sock, &magic,
sizeof(magic)) < 0)
245 err(
"It looks like you're trying to connect to an oldstyle server with a named export. This won't work.");
249 if(read(sock, &tmp,
sizeof(uint16_t)) < 0) {
250 err(
"Failed reading flags: %m");
252 *flags = ((u32)ntohs(tmp));
253 if((needed_flags & *flags) != needed_flags) {
257 fprintf(stderr,
"\nE: Server does not support listing exports\n");
261 client_flags = htonl(client_flags);
262 if (write(sock, &client_flags,
sizeof(client_flags)) < 0)
263 err(
"Failed/2.1: %m");
272 if (write(sock, &magic,
sizeof(magic)) < 0)
273 err(
"Failed/2.2: %m");
276 if (write(sock, &opt,
sizeof(opt)) < 0)
277 err(
"Failed/2.3: %m");
278 namesize = (u32)strlen(name);
279 namesize = ntohl(namesize);
280 if (write(sock, &namesize,
sizeof(namesize)) < 0)
281 err(
"Failed/2.4: %m");
282 if (write(sock, name, strlen(name)) < 0)
283 err(
"Failed/2.4: %m");
287 err(
"Not enough cliserv_magic");
289 err(
"It looks like you're trying to connect to a newstyle server with the oldstyle protocol. Try the -N option.");
294 if (read(sock, &size64,
sizeof(size64)) <= 0) {
296 err(
"Server closed connection");
297 err(
"Failed/3: %m\n");
301 if ((size64>>12) > (uint64_t)~0UL) {
302 printf(
"size = %luMB", (
unsigned long)(size64>>20));
303 err(
"Exported device is too big for me. Get 64-bit machine :-(\n");
305 printf(
"size = %luMB", (
unsigned long)(size64>>20));
308 if (read(sock, flags,
sizeof(*flags)) < 0)
309 err(
"Failed/4: %m\n");
310 *flags = ntohl(*flags);
312 if(read(sock, &tmp,
sizeof(tmp)) < 0)
313 err(
"Failed/4: %m\n");
314 *flags |= (uint32_t)ntohs(tmp);
317 if (read(sock, &buf, 124) < 0)
318 err(
"Failed/5: %m\n");
324 void setsizes(
int nbd, u64 size64,
int blocksize, u32 flags) {
328 if (size64>>12 > (uint64_t)~0UL)
329 err(
"Device too large.\n");
332 err(
"Ioctl/1.1a failed: %m\n");
333 size = (
unsigned long)(size64>>12);
335 err(
"Ioctl/1.1b failed: %m\n");
337 err(
"Ioctl/1.1c failed: %m\n");
338 fprintf(stderr,
"bs=%d, sz=%llu bytes\n", blocksize, 4096ULL*size);
346 if (ioctl(nbd, BLKROSET, (
unsigned long) &read_only) < 0)
347 err(
"Unable to set read-only attribute for device");
353 err(
"Ioctl NBD_SET_TIMEOUT failed: %m\n");
354 fprintf(stderr,
"timeout=%d\n", timeout);
360 err(
"Ioctl NBD_SET_SOCK failed: %m\n");
363 mlockall(MCL_CURRENT | MCL_FUTURE);
372 fd = open(file, O_WRONLY);
376 rc = write(fd, value, len) != (ssize_t) len;
385 va_start(ap, errmsg);
386 snprintf(tmp, 256,
"ERROR: %s\n\n", errmsg);
387 vfprintf(stderr, tmp, ap);
392 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");
393 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");
394 fprintf(stderr,
"Or : nbd-client -d nbd_device\n");
395 fprintf(stderr,
"Or : nbd-client -c nbd_device\n");
396 fprintf(stderr,
"Or : nbd-client -h|--help\n");
397 fprintf(stderr,
"Or : nbd-client -l|--list host\n");
398 fprintf(stderr,
"Default value for blocksize is 1024 (recommended for ethernet)\n");
399 fprintf(stderr,
"Allowed values for blocksize are 512,1024,2048,4096\n");
400 fprintf(stderr,
"Note, that kernel 2.4.2 and older ones do not work correctly with\n");
401 fprintf(stderr,
"blocksizes other than 1024 without patches\n");
402 fprintf(stderr,
"Default value for port with -N is 10809. Note that port must always be numeric\n");
406 int nbd = open(device, O_RDWR);
409 err(
"Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
410 printf(
"Disconnecting: que, ");
412 err(
"Ioctl failed: %m\n");
413 printf(
"disconnect, ");
415 err(
"Ioctl failed: %m\n");
418 err(
"Ioctl failed: %m\n");
422 int main(
int argc,
char *argv[]) {
438 uint32_t needed_flags=0;
442 struct option long_options[] = {
443 {
"block-size", required_argument, NULL,
'b' },
444 {
"check", required_argument, NULL,
'c' },
445 {
"disconnect", required_argument, NULL,
'd' },
446 {
"help", no_argument, NULL,
'h' },
447 {
"list", no_argument, NULL,
'l' },
448 {
"name", required_argument, NULL,
'N' },
449 {
"nofork", no_argument, NULL,
'n' },
450 {
"persist", no_argument, NULL,
'p' },
451 {
"sdp", no_argument, NULL,
'S' },
452 {
"swap", no_argument, NULL,
's' },
453 {
"timeout", required_argument, NULL,
't' },
459 while((c=getopt_long_only(argc, argv,
"-b:c:d:hlnN:pSst:", long_options, NULL))>=0) {
463 if(strchr(optarg,
'=')) {
466 fprintf(stderr,
"WARNING: old-style command-line argument encountered. This is deprecated.\n");
467 if(!strncmp(optarg,
"bs=", 3)) {
471 if(!strncmp(optarg,
"timeout=", 8)) {
475 usage(
"unknown option %s encountered", optarg);
478 switch(nonspecial++) {
485 if(!strtol(optarg, NULL, 0)) {
498 usage(
"too many non-option arguments specified");
504 blocksize=(int)strtol(optarg, NULL, 0);
542 timeout=strtol(optarg, NULL, 0);
545 fprintf(stderr,
"E: option eaten by 42 mice\n");
550 if((!port && !name) || !hostname || !nbddev) {
551 usage(
"not enough information specified");
555 sock =
opennet(hostname, port, sdp);
559 negotiate(sock, &size64, &flags, name, needed_flags, cflags, opts);
561 nbd = open(nbddev, O_RDWR);
563 err(
"Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
565 setsizes(nbd, size64, blocksize, flags);
570 if (
oom_adjust(
"/proc/self/oom_score_adj",
"-1000")) {
581 err(
"Cannot detach from terminal");
588 sigdelset(&block, SIGKILL);
589 sigdelset(&block, SIGTERM);
590 sigdelset(&block, SIGPIPE);
591 sigprocmask(SIG_SETMASK, &block, &old);
608 open(nbddev, O_RDONLY);
615 fprintf(stderr,
"nbd,%d: Kernel call returned: %d", getpid(), error);
625 close(sock); close(nbd);
627 fprintf(stderr,
" Reconnecting\n");
628 sock =
opennet(hostname, port, sdp);
633 nbd = open(nbddev, O_RDWR);
635 err(
"Cannot open NBD: %m");
636 negotiate(sock, &new_size, &new_flags, name, needed_flags, cflags, opts);
637 if (size64 != new_size) {
638 err(
"Size of the device changed. Bye");
651 fprintf(stderr,
"Kernel call returned.");
655 printf(
"Closing: que, ");
void setsizes(int nbd, u64 size64, int blocksize, u32 flags)
void disconnect(char *device)
#define NBD_REP_FLAG_ERROR
void finish_sock(int sock, int nbd, int swap)
void setmysockopt(int sock)
#define NBD_REP_ERR_POLICY
#define NBD_SET_SIZE_BLOCKS
void err_nonfatal(const char *s)
void usage(char *errmsg,...)
#define NBD_OPT_EXPORT_NAME
int check_conn(char *devname, int do_print)
#define NBD_FLAG_C_FIXED_NEWSTYLE
void err(const char *s) G_GNUC_NORETURN
#define NBD_FLAG_READ_ONLY
void set_timeout(int nbd, int timeout)
int main(int argc, char *argv[])
static int oom_adjust(const char *file, const char *value)
int opennet(char *name, char *portstr, int sdp)
#define NBD_FLAG_FIXED_NEWSTYLE
void negotiate(int sock, u64 *rsize64, u32 *flags, char *name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts)