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);
77 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)
142 const int BUF_SIZE = 1024;
146 if (write(sock, &magic,
sizeof(magic)) < 0)
147 err(
"Failed/2.2: %m");
151 if(write(sock, &opt,
sizeof(opt)) < 0) {
152 err(
"writing list option failed: %m");
156 if(write(sock, &len,
sizeof(len)) < 0) {
157 err(
"writing length failed: %m");
162 memset(buf, 0, 1024);
163 if(read(sock, &magic,
sizeof(magic)) < 0) {
164 err(
"Reading magic from server: %m");
166 if(read(sock, &opt_server,
sizeof(opt_server)) < 0) {
167 err(
"Reading option: %m");
169 if(read(sock, &reptype,
sizeof(reptype)) <0) {
170 err(
"Reading reply from server: %m");
172 if(read(sock, &len,
sizeof(len)) < 0) {
173 err(
"Reading length from server: %m");
177 reptype=ntohl(reptype);
179 err(
"Not enough magic from server");
184 fprintf(stderr,
"\nE: listing not allowed by server.\n");
187 fprintf(stderr,
"\nE: unexpected error from server.\n");
190 if(len > 0 && len < BUF_SIZE) {
191 if(len=read(sock, buf, len) < 0) {
192 fprintf(stderr,
"\nE: could not read error message from server\n");
195 fprintf(stderr,
"Server said: %s\n", buf);
201 err(
"Server sent us a reply we don't understand!");
203 if(read(sock, &len,
sizeof(len)) < 0) {
204 fprintf(stderr,
"\nE: could not read export name length from server\n");
208 if (len >= BUF_SIZE) {
209 fprintf(stderr,
"\nE: export name on server too long\n");
212 if(read(sock, buf, len) < 0) {
213 fprintf(stderr,
"\nE: could not read export name from server\n");
224 if (write(sock, &magic,
sizeof(magic)) < 0)
225 err(
"Failed/2.2: %m");
226 if (write(sock, &opt,
sizeof(opt)) < 0)
227 err(
"Failed writing abort");
228 if (write(sock, &len,
sizeof(len)) < 0)
229 err(
"Failed writing length");
232 void negotiate(
int sock, u64 *rsize64, u32 *flags,
char* name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts) {
235 char buf[256] =
"\0\0\0\0\0\0\0\0\0";
237 printf(
"Negotiation: ");
238 if (read(sock, buf, 8) < 0)
241 err(
"Server closed connection");
243 err(
"INIT_PASSWD bad");
245 if (read(sock, &magic,
sizeof(magic)) < 0)
254 err(
"It looks like you're trying to connect to an oldstyle server with a named export. This won't work.");
258 if(read(sock, &tmp,
sizeof(uint16_t)) < 0) {
259 err(
"Failed reading flags: %m");
261 *flags = ((u32)ntohs(tmp));
262 if((needed_flags & *flags) != needed_flags) {
266 fprintf(stderr,
"\nE: Server does not support listing exports\n");
270 client_flags = htonl(client_flags);
271 if (write(sock, &client_flags,
sizeof(client_flags)) < 0)
272 err(
"Failed/2.1: %m");
281 if (write(sock, &magic,
sizeof(magic)) < 0)
282 err(
"Failed/2.2: %m");
285 if (write(sock, &opt,
sizeof(opt)) < 0)
286 err(
"Failed/2.3: %m");
287 namesize = (u32)strlen(name);
288 namesize = ntohl(namesize);
289 if (write(sock, &namesize,
sizeof(namesize)) < 0)
290 err(
"Failed/2.4: %m");
291 if (write(sock, name, strlen(name)) < 0)
292 err(
"Failed/2.4: %m");
296 err(
"Not enough cliserv_magic");
298 err(
"It looks like you're trying to connect to a newstyle server with the oldstyle protocol. Try the -N option.");
303 if (read(sock, &size64,
sizeof(size64)) <= 0) {
305 err(
"Server closed connection");
306 err(
"Failed/3: %m\n");
310 if ((size64>>12) > (uint64_t)~0UL) {
311 printf(
"size = %luMB", (
unsigned long)(size64>>20));
312 err(
"Exported device is too big for me. Get 64-bit machine :-(\n");
314 printf(
"size = %luMB", (
unsigned long)(size64>>20));
317 if (read(sock, flags,
sizeof(*flags)) < 0)
318 err(
"Failed/4: %m\n");
319 *flags = ntohl(*flags);
321 if(read(sock, &tmp,
sizeof(tmp)) < 0)
322 err(
"Failed/4: %m\n");
323 *flags |= (uint32_t)ntohs(tmp);
326 if (read(sock, &buf, 124) < 0)
327 err(
"Failed/5: %m\n");
333 void setsizes(
int nbd, u64 size64,
int blocksize, u32 flags) {
337 if (size64>>12 > (uint64_t)~0UL)
338 err(
"Device too large.\n");
341 err(
"Ioctl/1.1a failed: %m\n");
342 size = (
unsigned long)(size64>>12);
344 err(
"Ioctl/1.1b failed: %m\n");
346 err(
"Ioctl/1.1c failed: %m\n");
347 fprintf(stderr,
"bs=%d, sz=%llu bytes\n", blocksize, 4096ULL*size);
355 if (ioctl(nbd, BLKROSET, (
unsigned long) &read_only) < 0)
356 err(
"Unable to set read-only attribute for device");
362 err(
"Ioctl NBD_SET_TIMEOUT failed: %m\n");
363 fprintf(stderr,
"timeout=%d\n", timeout);
369 err(
"Ioctl NBD_SET_SOCK failed: %m\n");
372 mlockall(MCL_CURRENT | MCL_FUTURE);
381 fd = open(file, O_WRONLY);
385 rc = write(fd, value, len) != (ssize_t) len;
394 va_start(ap, errmsg);
395 snprintf(tmp, 256,
"ERROR: %s\n\n", errmsg);
396 vfprintf(stderr, tmp, ap);
401 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] [-systemd-mark|-m]\n");
402 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");
403 fprintf(stderr,
"Or : nbd-client -d nbd_device\n");
404 fprintf(stderr,
"Or : nbd-client -c nbd_device\n");
405 fprintf(stderr,
"Or : nbd-client -h|--help\n");
406 fprintf(stderr,
"Or : nbd-client -l|--list host\n");
407 fprintf(stderr,
"Default value for blocksize is 1024 (recommended for ethernet)\n");
408 fprintf(stderr,
"Allowed values for blocksize are 512,1024,2048,4096\n");
409 fprintf(stderr,
"Note, that kernel 2.4.2 and older ones do not work correctly with\n");
410 fprintf(stderr,
"blocksizes other than 1024 without patches\n");
411 fprintf(stderr,
"Default value for port with -N is 10809. Note that port must always be numeric\n");
415 int nbd = open(device, O_RDWR);
418 err(
"Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
419 printf(
"disconnect, ");
421 err(
"Ioctl failed: %m\n");
424 err(
"Ioctl failed: %m\n");
428 int main(
int argc,
char *argv[]) {
444 uint32_t needed_flags=0;
449 struct option long_options[] = {
450 {
"block-size", required_argument, NULL,
'b' },
451 {
"check", required_argument, NULL,
'c' },
452 {
"disconnect", required_argument, NULL,
'd' },
453 {
"help", no_argument, NULL,
'h' },
454 {
"list", no_argument, NULL,
'l' },
455 {
"name", required_argument, NULL,
'N' },
456 {
"nofork", no_argument, NULL,
'n' },
457 {
"persist", no_argument, NULL,
'p' },
458 {
"sdp", no_argument, NULL,
'S' },
459 {
"swap", no_argument, NULL,
's' },
460 {
"systemd-mark", no_argument, NULL,
'm' },
461 {
"timeout", required_argument, NULL,
't' },
467 while((c=getopt_long_only(argc, argv,
"-b:c:d:hlnN:pSst:", long_options, NULL))>=0) {
471 if(strchr(optarg,
'=')) {
474 fprintf(stderr,
"WARNING: old-style command-line argument encountered. This is deprecated.\n");
475 if(!strncmp(optarg,
"bs=", 3)) {
479 if(!strncmp(optarg,
"timeout=", 8)) {
483 usage(
"unknown option %s encountered", optarg);
486 switch(nonspecial++) {
493 if(!strtol(optarg, NULL, 0)) {
506 usage(
"too many non-option arguments specified");
512 blocksize=(int)strtol(optarg, NULL, 0);
553 timeout=strtol(optarg, NULL, 0);
556 fprintf(stderr,
"E: option eaten by 42 mice\n");
561 if((!port && !name) || !hostname || !nbddev) {
562 usage(
"not enough information specified");
566 sock =
opennet(hostname, port, sdp);
570 negotiate(sock, &size64, &flags, name, needed_flags, cflags, opts);
572 nbd = open(nbddev, O_RDWR);
574 err(
"Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
576 setsizes(nbd, size64, blocksize, flags);
581 if (
oom_adjust(
"/proc/self/oom_score_adj",
"-1000")) {
592 err(
"Cannot detach from terminal");
595 memset(&sa, 0,
sizeof(sa));
596 sa.sa_handler = SIG_IGN;
597 sigaction(SIGCHLD, &sa, NULL);
603 sigdelset(&block, SIGKILL);
604 sigdelset(&block, SIGTERM);
605 sigdelset(&block, SIGPIPE);
606 sigprocmask(SIG_SETMASK, &block, &old);
623 open(nbddev, O_RDONLY);
630 fprintf(stderr,
"nbd,%d: Kernel call returned: %d", getpid(), error);
640 close(sock); close(nbd);
642 fprintf(stderr,
" Reconnecting\n");
643 sock =
opennet(hostname, port, sdp);
648 nbd = open(nbddev, O_RDWR);
650 err(
"Cannot open NBD: %m");
651 negotiate(sock, &new_size, &new_flags, name, needed_flags, cflags, opts);
652 if (size64 != new_size) {
653 err(
"Size of the device changed. Bye");
666 fprintf(stderr,
"Kernel call returned.");
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)