24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
27 #include <sys/types.h>
29 #include <netinet/tcp.h>
30 #include <netinet/in.h>
37 #include <sys/mount.h>
46 #include <linux/ioctl.h>
47 #define MY_NAME "nbd_client"
54 #define NBDC_DO_LIST 1
62 if( (p=strrchr(devname,
'/')) ) {
65 if((p=strchr(devname,
'p'))) {
69 snprintf(buf, 256,
"/sys/block/%s/pid", devname);
70 if((fd=open(buf, O_RDONLY))<0) {
77 len=read(fd, buf, 256);
79 perror(
"could not read from server");
82 buf[(len < 256) ? len : 255]=
'\0';
83 if(do_print) printf(
"%s\n", buf);
88 int opennet(
char *name,
char* portstr,
int sdp) {
90 struct addrinfo hints;
91 struct addrinfo *ai = NULL;
92 struct addrinfo *rp = NULL;
95 memset(&hints,
'\0',
sizeof(hints));
96 hints.ai_family = AF_UNSPEC;
97 hints.ai_socktype = SOCK_STREAM;
99 hints.ai_protocol = IPPROTO_TCP;
101 e = getaddrinfo(name, portstr, &hints, &ai);
104 fprintf(stderr,
"getaddrinfo failed: %s\n", gai_strerror(e));
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;
116 err(
"Can't do SDP: I was not compiled with SDP support!");
120 for(rp = ai; rp != NULL; rp = rp->ai_next) {
121 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
126 if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
146 struct sockaddr_un un_addr;
147 memset(&un_addr, 0,
sizeof(un_addr));
149 un_addr.sun_family = AF_UNIX;
150 if (strnlen(path,
sizeof(un_addr.sun_path)) ==
sizeof(un_addr.sun_path)) {
155 strncpy(un_addr.sun_path, path,
sizeof(un_addr.sun_path) - 1);
157 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
162 if (connect(sock, &un_addr,
sizeof(un_addr)) == -1) {
177 const int BUF_SIZE = 1024;
181 if (write(sock, &magic,
sizeof(magic)) < 0)
182 err(
"Failed/2.2: %m");
186 if(write(sock, &opt,
sizeof(opt)) < 0) {
187 err(
"writing list option failed: %m");
191 if(write(sock, &len,
sizeof(len)) < 0) {
192 err(
"writing length failed: %m");
197 memset(buf, 0, 1024);
198 if(read(sock, &magic,
sizeof(magic)) < 0) {
199 err(
"Reading magic from server: %m");
201 if(read(sock, &opt_server,
sizeof(opt_server)) < 0) {
202 err(
"Reading option: %m");
204 if(read(sock, &reptype,
sizeof(reptype)) <0) {
205 err(
"Reading reply from server: %m");
207 if(read(sock, &len,
sizeof(len)) < 0) {
208 err(
"Reading length from server: %m");
212 reptype=ntohl(reptype);
214 err(
"Not enough magic from server");
219 fprintf(stderr,
"\nE: listing not allowed by server.\n");
222 fprintf(stderr,
"\nE: unexpected error from server.\n");
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");
230 fprintf(stderr,
"Server said: %s\n", buf);
237 err(
"Server sent us a reply we don't understand!");
239 if(read(sock, &len,
sizeof(len)) < 0) {
240 fprintf(stderr,
"\nE: could not read export name length from server\n");
244 if (len >= BUF_SIZE) {
245 fprintf(stderr,
"\nE: export name on server too long\n");
248 if(read(sock, buf, len) < 0) {
249 fprintf(stderr,
"\nE: could not read export name from server\n");
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");
268 void negotiate(
int sock, u64 *rsize64, uint16_t *flags,
char* name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts) {
271 uint16_t global_flags;
272 char buf[256] =
"\0\0\0\0\0\0\0\0\0";
276 printf(
"Negotiation: ");
279 err(
"INIT_PASSWD bad");
281 readit(sock, &magic,
sizeof(magic));
285 err(
"It looks like you're trying to connect to an oldstyle server. This is no longer supported since nbd 3.10.");
289 readit(sock, &tmp,
sizeof(uint16_t));
290 global_flags = ntohs(tmp);
291 if((needed_flags & global_flags) != needed_flags) {
295 fprintf(stderr,
"\nE: Server does not support listing exports\n");
302 client_flags = htonl(client_flags);
303 if (write(sock, &client_flags,
sizeof(client_flags)) < 0)
304 err(
"Failed/2.1: %m");
313 if (write(sock, &magic,
sizeof(magic)) < 0)
314 err(
"Failed/2.2: %m");
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");
326 readit(sock, &size64,
sizeof(size64));
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");
333 printf(
"size = %luMB", (
unsigned long)(size64>>20));
335 readit(sock, &tmp,
sizeof(tmp));
336 *flags = (uint32_t)ntohs(tmp);
338 if (!(global_flags & NBD_FLAG_NO_ZEROES)) {
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);
350 fprintf(stderr,
"while opening %s: ",
SYSCONFDIR "/nbdtab");
351 perror(
"could not open config file");
354 off_t size = lseek(fd, 0, SEEK_END);
355 lseek(fd, 0, SEEK_SET);
357 char *fsep =
"\n\t# ";
361 perror(
"E: mmap'ing nbdtab");
365 data = mmap(NULL, (
size_t)size, PROT_READ, MAP_SHARED, fd, 0);
366 char *loc = strstr((
const char*)data, cfgname);
370 size_t l = strlen(cfgname) + 6;
371 *dev_ptr = malloc(l);
372 snprintf(*dev_ptr, l,
"/dev/%s", cfgname);
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
378 line_len = strcspn(loc, lsep);
384 *hostn_ptr = strndup(loc, field_len);
388 *name_ptr = strndup(loc, field_len);
389 if(ws_len + field_len > line_len) {
400 if(!strncmp(loc,
"bs=", 3)) {
401 *bs = (int)strtol(loc+3, &loc, 0);
404 if(!strncmp(loc,
"timeout=", 8)) {
405 *timeout = (int)strtol(loc+8, &loc, 0);
408 if(!strncmp(loc,
"port=", 5)) {
409 *port = strndup(loc+5, strcspn(loc+5,
","));
412 if(!strncmp(loc,
"persist", 7)) {
417 if(!strncmp(loc,
"swap", 4)) {
422 if(!strncmp(loc,
"sdp", 3)) {
427 if(!strncmp(loc,
"unix", 4)) {
433 l = strcspn(loc,
",");
435 char* s = strndup(loc, l);
436 fprintf(stderr,
"Warning: unknown option '%s' found in nbdtab file", s);
444 }
while(strcspn(loc, lsep) > 0);
456 void setsizes(
int nbd, u64 size64,
int blocksize, u32 flags) {
460 if (size64>>12 > (uint64_t)~0UL)
461 err(
"Device too large.\n");
464 err(
"Ioctl/1.1a failed: %m\n");
465 size = (
unsigned long)(size64>>12);
467 err(
"Ioctl/1.1b failed: %m\n");
469 err(
"Ioctl/1.1c failed: %m\n");
470 fprintf(stderr,
"bs=%d, sz=%llu bytes\n", blocksize, 4096ULL*size);
478 if (ioctl(nbd, BLKROSET, (
unsigned long) &read_only) < 0)
479 err(
"Unable to set read-only attribute for device");
485 err(
"Ioctl NBD_SET_TIMEOUT failed: %m\n");
486 fprintf(stderr,
"timeout=%d\n", timeout);
492 err(
"Ioctl NBD_SET_SOCK failed: %m\n");
496 mlockall(MCL_CURRENT | MCL_FUTURE);
506 fd = open(file, O_WRONLY);
510 rc = write(fd, value, len) != (ssize_t) len;
519 va_start(ap, errmsg);
520 snprintf(tmp, 256,
"ERROR: %s\n\n", errmsg);
521 vfprintf(stderr, tmp, ap);
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");
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");
541 int nbd = open(device, O_RDWR);
544 err(
"Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
545 printf(
"disconnect, ");
547 err(
"Ioctl failed: %m\n");
550 err(
"Ioctl failed: %m\n");
554 int main(
int argc,
char *argv[]) {
571 uint16_t needed_flags=0;
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' },
595 while((c=getopt_long_only(argc, argv,
"-b:c:d:hlnN:pSst:u", long_options, NULL))>=0) {
599 if(strchr(optarg,
'=')) {
602 fprintf(stderr,
"WARNING: old-style command-line argument encountered. This is deprecated.\n");
603 if(!strncmp(optarg,
"bs=", 3)) {
607 if(!strncmp(optarg,
"timeout=", 8)) {
611 usage(
"unknown option %s encountered", optarg);
614 switch(nonspecial++) {
621 if(!strtol(optarg, NULL, 0)) {
634 usage(
"too many non-option arguments specified");
640 blocksize=(int)strtol(optarg, NULL, 0);
675 timeout=strtol(optarg, NULL, 0);
681 fprintf(stderr,
"E: option eaten by 42 mice\n");
688 err(
"swap option unsupported on Android because mlockall is unsupported.");
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);
698 usage(
"not enough information specified, and argument didn't look like an nbd device");
703 usage(
"no information specified");
708 printf(
"Warning: the oldstyle protocol is no longer supported.\nThis method now uses the newstyle protocol with a default export\n");
714 sock =
opennet(hostname, port, sdp);
718 negotiate(sock, &size64, &flags, name, needed_flags, cflags, opts);
720 nbd = open(nbddev, O_RDWR);
722 err(
"Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
724 setsizes(nbd, size64, blocksize, flags);
729 if (
oom_adjust(
"/proc/self/oom_score_adj",
"-1000")) {
740 err(
"Cannot detach from terminal");
743 memset(&sa, 0,
sizeof(sa));
744 sa.sa_handler = SIG_IGN;
745 sigaction(SIGCHLD, &sa, NULL);
751 sigdelset(&block, SIGKILL);
752 sigdelset(&block, SIGTERM);
753 sigdelset(&block, SIGPIPE);
754 sigprocmask(SIG_SETMASK, &block, &old);
768 struct timespec req = {
770 .tv_nsec = 100000000,
773 nanosleep(&req, NULL);
775 open(nbddev, O_RDONLY);
782 fprintf(stderr,
"nbd,%d: Kernel call returned: %d", getpid(), error);
792 close(sock); close(nbd);
794 fprintf(stderr,
" Reconnecting\n");
798 sock =
opennet(hostname, port, sdp);
803 nbd = open(nbddev, O_RDWR);
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");
821 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 negotiate(int sock, u64 *rsize64, uint16_t *flags, char *name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts)
#define NBD_FLAG_C_NO_ZEROES
#define NBD_FLAG_NO_ZEROES
#define SYSCONFDIR
Default position of the config file.
void finish_sock(int sock, int nbd, int swap)
#define NBD_REP_ERR_POLICY
#define NBD_SET_SIZE_BLOCKS
void usage(char *errmsg,...)
#define NBD_OPT_EXPORT_NAME
void setmysockopt(int sock)
void err_nonfatal(const char *s)
void readit(int f, void *buf, size_t len)
Read data from a file descriptor into a buffer.
int check_conn(char *devname, int do_print)
#define NBD_FLAG_C_FIXED_NEWSTYLE
#define NBD_FLAG_READ_ONLY
uint64_t ntohll(uint64_t a)
void set_timeout(int nbd, int timeout)
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 openunix(const char *path)
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 logging(const char *name)