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 <inttypes.h>
34 #include <stdio.h>
35 #include <fcntl.h>
36 #include <syslog.h>
37 #include <stdlib.h>
38 #include <sys/mount.h>
39 #include <sys/mman.h>
40 #include <signal.h>
41 #include <errno.h>
42 #include <getopt.h>
43 #include <stdarg.h>
44 #include <stdbool.h>
45 #include <time.h>
46
47 #include <linux/ioctl.h>
48
49 #if HAVE_NETLINK
50 #include "nbd-netlink.h"
51 #include <netlink/netlink.h>
52 #include <netlink/genl/genl.h>
53 #include <netlink/genl/ctrl.h>
54 #endif
55
56 #define MY_NAME "nbd_client"
57 #include "cliserv.h"
58
59 #if HAVE_GNUTLS && !defined(NOTLS)
60 #include "crypto-gnutls.h"
61 #endif
62
63 #ifdef WITH_SDP
64 #include <sdp_inet.h>
65 #endif
66
67 #include "nbdclt.h"
68 #include "nbdtab_parser.tab.h"
69
70 CLIENT* cur_client;
71 extern FILE *yyin, *yyout;
72 bool found_config = false;
73 bool parse_error = false;
74
75 #define SET_PROP(str, member, rval) if(!strcmp(property, str)) { cur_client->member = (rval); return; }
nbdtab_set_property(char * property,char * val)76 void nbdtab_set_property(char *property, char *val) {
77 if(found_config) return;
78 SET_PROP("port", port, val);
79 SET_PROP("certfile", cert, val);
80 SET_PROP("keyfile", key, val);
81 SET_PROP("cacertfile", cacert, val);
82 SET_PROP("tlshostname", tlshostn, val);
83 SET_PROP("bs", bs, strtol(val, NULL, 10));
84 SET_PROP("timeout", timeout, strtol(val, NULL, 10));
85 SET_PROP("conns", nconn, strtol(val, NULL, 10));
86 if(*property != '_') {
87 fprintf(stderr, "Warning: unknown option '%s' found in nbdtab file", property);
88 }
89 }
90 #undef SET_PROP
91
92 #define SET_FLAG(str, member) if(!strcmp(property, str)) { cur_client->member = true; return; }
nbdtab_set_flag(char * property)93 void nbdtab_set_flag(char *property) {
94 if(found_config) return;
95 SET_FLAG("no_optgo", no_optgo);
96 SET_FLAG("persist", persist);
97 SET_FLAG("swap", swap);
98 SET_FLAG("sdp", sdp);
99 SET_FLAG("unix", b_unix);
100 SET_FLAG("preinit", preinit);
101 SET_FLAG("tls", tls);
102 if(*property != '_') {
103 fprintf(stderr, "Warning: unknown option '%s' found in nbdtab file", property);
104 }
105 }
106
nbdtab_commit_line(char * devn,char * hostn,char * exportname)107 void nbdtab_commit_line(char *devn, char *hostn, char *exportname) {
108 if(!strncmp(devn, "/dev/", 5)) {
109 devn += 5;
110 }
111 if(!strcmp(cur_client->dev, devn)) {
112 found_config = true;
113 cur_client->hostn = hostn;
114 cur_client->name = exportname;
115 } else {
116 if(!found_config) {
117 char *tmp = cur_client->dev;
118 memset(cur_client, 0, sizeof(CLIENT));
119 cur_client->bs = 512;
120 cur_client->nconn = 1;
121 cur_client->dev = tmp;
122 }
123 }
124 return;
125 }
126
yyerror(char * msg)127 void yyerror(char *msg) {
128 parse_error = true;
129 fprintf(stderr, "parse error parsing " SYSCONFDIR "/nbdtab: %s", msg);
130 }
131
132 #undef SET_FLAG
133
134 #define NBDC_DO_LIST 1
135
136 #if HAVE_NETLINK
callback(struct nl_msg * msg,void * arg)137 static int callback(struct nl_msg *msg, void *arg) {
138 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
139 struct nlattr *msg_attr[NBD_ATTR_MAX + 1];
140 int ret;
141 uint32_t index;
142
143 ret = nla_parse(msg_attr, NBD_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
144 genlmsg_attrlen(gnlh, 0), NULL);
145 if (ret)
146 err("Invalid response from the kernel\n");
147 if (!msg_attr[NBD_ATTR_INDEX])
148 err("Did not receive index from the kernel\n");
149 index = nla_get_u32(msg_attr[NBD_ATTR_INDEX]);
150 printf("Connected /dev/nbd%d\n", (int)index);
151 return NL_OK;
152 }
153
get_nbd_socket(int * driver_id)154 static struct nl_sock *get_nbd_socket(int *driver_id) {
155 struct nl_sock *socket;
156
157 socket = nl_socket_alloc();
158 if (!socket)
159 err("Couldn't allocate netlink socket\n");
160
161 if (genl_connect(socket))
162 err("Couldn't connect to the generic netlink socket\n");
163 *driver_id = genl_ctrl_resolve(socket, "nbd");
164 if (*driver_id < 0)
165 err("Couldn't resolve the nbd netlink family, make sure the nbd module is loaded and your nbd driver supports the netlink interface.\n");
166 return socket;
167 }
168
netlink_configure(int index,int * sockfds,int num_connects,u64 size64,int blocksize,uint16_t flags,int timeout)169 static void netlink_configure(int index, int *sockfds, int num_connects,
170 u64 size64, int blocksize, uint16_t flags,
171 int timeout) {
172 struct nl_sock *socket;
173 struct nlattr *sock_attr;
174 struct nl_msg *msg;
175 int driver_id, i;
176
177 socket = get_nbd_socket(&driver_id);
178 nl_socket_modify_cb(socket, NL_CB_VALID, NL_CB_CUSTOM, callback, NULL);
179
180 msg = nlmsg_alloc();
181 if (!msg)
182 err("Couldn't allocate netlink message\n");
183 genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, driver_id, 0, 0,
184 NBD_CMD_CONNECT, 0);
185 if (index >= 0)
186 NLA_PUT_U32(msg, NBD_ATTR_INDEX, index);
187 NLA_PUT_U64(msg, NBD_ATTR_SIZE_BYTES, size64);
188 NLA_PUT_U64(msg, NBD_ATTR_BLOCK_SIZE_BYTES, blocksize);
189 NLA_PUT_U64(msg, NBD_ATTR_SERVER_FLAGS, flags);
190 if (timeout)
191 NLA_PUT_U64(msg, NBD_ATTR_TIMEOUT, timeout);
192
193 sock_attr = nla_nest_start(msg, NBD_ATTR_SOCKETS);
194 if (!sock_attr)
195 err("Couldn't nest the sockets for our connection\n");
196 for (i = 0; i < num_connects; i++) {
197 struct nlattr *sock_opt;
198 sock_opt = nla_nest_start(msg, NBD_SOCK_ITEM);
199 if (!sock_opt)
200 err("Couldn't nest the sockets for our connection\n");
201 NLA_PUT_U32(msg, NBD_SOCK_FD, sockfds[i]);
202 nla_nest_end(msg, sock_opt);
203 }
204 nla_nest_end(msg, sock_attr);
205
206 if (nl_send_sync(socket, msg) < 0)
207 err("Failed to setup device, check dmesg\n");
208 return;
209 nla_put_failure:
210 err("Failed to create netlink message\n");
211 }
212
netlink_disconnect(char * nbddev)213 static void netlink_disconnect(char *nbddev) {
214 struct nl_sock *socket;
215 struct nl_msg *msg;
216 int driver_id;
217
218 int index = -1;
219 if (nbddev) {
220 if (sscanf(nbddev, "/dev/nbd%d", &index) != 1)
221 err("Invalid nbd device target\n");
222 }
223 if (index < 0)
224 err("Invalid nbd device target\n");
225
226 socket = get_nbd_socket(&driver_id);
227
228 msg = nlmsg_alloc();
229 if (!msg)
230 err("Couldn't allocate netlink message\n");
231 genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, driver_id, 0, 0,
232 NBD_CMD_DISCONNECT, 0);
233 NLA_PUT_U32(msg, NBD_ATTR_INDEX, index);
234 if (nl_send_sync(socket, msg) < 0)
235 err("Failed to disconnect device, check dmsg\n");
236 nl_socket_free(socket);
237 return;
238 nla_put_failure:
239 err("Failed to create netlink message\n");
240 }
241 #else
netlink_configure(int index,int * sockfds,int num_connects,u64 size64,int blocksize,uint16_t flags,int timeout)242 static void netlink_configure(int index, int *sockfds, int num_connects,
243 u64 size64, int blocksize, uint16_t flags,
244 int timeout)
245 {
246 }
247
netlink_disconnect(char * nbddev)248 static void netlink_disconnect(char *nbddev)
249 {
250 }
251 #endif /* HAVE_NETLINK */
252
check_conn(char * devname,int do_print)253 int check_conn(char* devname, int do_print) {
254 char buf[256];
255 char* p;
256 int fd;
257 int len;
258
259 if( (p=strrchr(devname, '/')) ) {
260 devname=p+1;
261 }
262 if((p=strchr(devname, 'p'))) {
263 /* We can't do checks on partitions. */
264 *p='\0';
265 }
266 snprintf(buf, 256, "/sys/block/%s/pid", devname);
267 if((fd=open(buf, O_RDONLY))<0) {
268 if(errno==ENOENT) {
269 return 1;
270 } else {
271 return 2;
272 }
273 }
274 len=read(fd, buf, 256);
275 if(len < 0) {
276 perror("could not read from server");
277 close(fd);
278 return 2;
279 }
280 buf[(len < 256) ? len : 255]='\0';
281 if(do_print) printf("%s\n", buf);
282 close(fd);
283 return 0;
284 }
285
opennet(char * name,char * portstr,int sdp)286 int opennet(char *name, char* portstr, int sdp) {
287 int sock;
288 struct addrinfo hints;
289 struct addrinfo *ai = NULL;
290 struct addrinfo *rp = NULL;
291 int e;
292
293 memset(&hints,'\0',sizeof(hints));
294 hints.ai_family = AF_UNSPEC;
295 hints.ai_socktype = SOCK_STREAM;
296 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
297 hints.ai_protocol = IPPROTO_TCP;
298
299 e = getaddrinfo(name, portstr, &hints, &ai);
300
301 if(e != 0) {
302 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
303 freeaddrinfo(ai);
304 return -1;
305 }
306
307 if(sdp) {
308 #ifdef WITH_SDP
309 if (ai->ai_family == AF_INET)
310 ai->ai_family = AF_INET_SDP;
311 else (ai->ai_family == AF_INET6)
312 ai->ai_family = AF_INET6_SDP;
313 #else
314 err("Can't do SDP: I was not compiled with SDP support!");
315 #endif
316 }
317
318 for(rp = ai; rp != NULL; rp = rp->ai_next) {
319 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
320
321 if(sock == -1)
322 continue; /* error */
323
324 if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
325 break; /* success */
326
327 close(sock);
328 }
329
330 if (rp == NULL) {
331 err_nonfatal("Socket failed: %m");
332 sock = -1;
333 goto err;
334 }
335
336 setmysockopt(sock);
337 err:
338 freeaddrinfo(ai);
339 return sock;
340 }
341
openunix(const char * path)342 int openunix(const char *path) {
343 int sock;
344 struct sockaddr_un un_addr;
345 memset(&un_addr, 0, sizeof(un_addr));
346
347 un_addr.sun_family = AF_UNIX;
348 if (strnlen(path, sizeof(un_addr.sun_path)) == sizeof(un_addr.sun_path)) {
349 err_nonfatal("UNIX socket path too long");
350 return -1;
351 }
352
353 strncpy(un_addr.sun_path, path, sizeof(un_addr.sun_path) - 1);
354
355 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
356 err_nonfatal("SOCKET failed");
357 return -1;
358 };
359
360 if (connect(sock, &un_addr, sizeof(un_addr)) == -1) {
361 err_nonfatal("CONNECT failed");
362 close(sock);
363 return -1;
364 }
365 return sock;
366 }
367
send_request(int sock,uint32_t opt,ssize_t datasize,void * data)368 void send_request(int sock, uint32_t opt, ssize_t datasize, void* data) {
369 struct {
370 uint64_t magic;
371 uint32_t opt;
372 uint32_t datasize;
373 } __attribute__((packed)) header = {
374 ntohll(opts_magic),
375 ntohl(opt),
376 ntohl(datasize),
377 };
378 if(datasize < 0) {
379 datasize = strlen((char*)data);
380 header.datasize = htonl(datasize);
381 }
382 writeit(sock, &header, sizeof(header));
383 if(data != NULL) {
384 writeit(sock, data, datasize);
385 }
386 }
387
send_info_request(int sock,uint32_t opt,int n_reqs,uint16_t * reqs,char * name)388 void send_info_request(int sock, uint32_t opt, int n_reqs, uint16_t* reqs, char* name) {
389 uint16_t rlen = htons(n_reqs);
390 uint32_t nlen = htonl(strlen(name));
391
392 send_request(sock, opt, sizeof(uint32_t) + strlen(name) + sizeof(uint16_t) + n_reqs * sizeof(uint16_t), NULL);
393 writeit(sock, &nlen, sizeof(nlen));
394 writeit(sock, name, strlen(name));
395 writeit(sock, &rlen, sizeof(rlen));
396 if(n_reqs > 0) {
397 writeit(sock, reqs, n_reqs * sizeof(uint16_t));
398 }
399 }
400
401 struct reply {
402 uint64_t magic;
403 uint32_t opt;
404 uint32_t reply_type;
405 uint32_t datasize;
406 char data[];
407 } __attribute__((packed));
408
read_reply(int sock)409 struct reply* read_reply(int sock) {
410 struct reply *retval = malloc(sizeof(struct reply));
411 readit(sock, retval, sizeof(*retval));
412 retval->magic = ntohll(retval->magic);
413 retval->opt = ntohl(retval->opt);
414 retval->reply_type = ntohl(retval->reply_type);
415 retval->datasize = ntohl(retval->datasize);
416 if (retval->magic != rep_magic) {
417 fprintf(stderr, "E: received invalid negotiation magic %" PRIu64 " (expected %" PRIu64 ")", retval->magic, rep_magic);
418 exit(EXIT_FAILURE);
419 }
420 if (retval->datasize > 0) {
421 retval = realloc(retval, sizeof(struct reply) + retval->datasize);
422 readit(sock, &(retval->data), retval->datasize);
423 }
424 return retval;
425 }
426
ask_list(int sock)427 void ask_list(int sock) {
428 uint32_t opt_server;
429 uint32_t len;
430 uint32_t lenn;
431 uint32_t reptype;
432 uint64_t magic;
433 int rlen;
434 const int BUF_SIZE = 1024;
435 char buf[BUF_SIZE];
436
437 send_request(sock, NBD_OPT_LIST, 0, NULL);
438 /* newline, move away from the "Negotiation:" line */
439 printf("\n");
440 do {
441 memset(buf, 0, 1024);
442 if(read(sock, &magic, sizeof(magic)) < 0) {
443 err("Reading magic from server: %m");
444 }
445 if(read(sock, &opt_server, sizeof(opt_server)) < 0) {
446 err("Reading option: %m");
447 }
448 if(read(sock, &reptype, sizeof(reptype)) <0) {
449 err("Reading reply from server: %m");
450 }
451 if(read(sock, &len, sizeof(len)) < 0) {
452 err("Reading length from server: %m");
453 }
454 magic=ntohll(magic);
455 len=ntohl(len);
456 reptype=ntohl(reptype);
457 if(magic != rep_magic) {
458 err("Not enough magic from server");
459 }
460 if(reptype & NBD_REP_FLAG_ERROR) {
461 switch(reptype) {
462 case NBD_REP_ERR_POLICY:
463 fprintf(stderr, "\nE: listing not allowed by server.\n");
464 break;
465 default:
466 fprintf(stderr, "\nE: unexpected error from server.\n");
467 break;
468 }
469 if(len > 0 && len < BUF_SIZE) {
470 if((rlen=read(sock, buf, len)) < 0) {
471 fprintf(stderr, "\nE: could not read error message from server\n");
472 } else {
473 buf[rlen] = '\0';
474 fprintf(stderr, "Server said: %s\n", buf);
475 }
476 }
477 exit(EXIT_FAILURE);
478 } else {
479 if(reptype != NBD_REP_ACK) {
480 if(reptype != NBD_REP_SERVER) {
481 err("Server sent us a reply we don't understand!");
482 }
483 if(read(sock, &lenn, sizeof(lenn)) < 0) {
484 fprintf(stderr, "\nE: could not read export name length from server\n");
485 exit(EXIT_FAILURE);
486 }
487 lenn=ntohl(lenn);
488 if (lenn >= BUF_SIZE) {
489 fprintf(stderr, "\nE: export name on server too long\n");
490 exit(EXIT_FAILURE);
491 }
492 if(read(sock, buf, lenn) < 0) {
493 fprintf(stderr, "\nE: could not read export name from server\n");
494 exit(EXIT_FAILURE);
495 }
496 buf[lenn] = 0;
497 printf("%s", buf);
498 len -= lenn;
499 len -= sizeof(lenn);
500 if(len > 0) {
501 if(read(sock, buf, len) < 0) {
502 fprintf(stderr, "\nE: could not read export description from server\n");
503 exit(EXIT_FAILURE);
504 }
505 buf[len] = 0;
506 printf(": %s\n", buf);
507 } else {
508 printf("\n");
509 }
510 }
511 }
512 } while(reptype != NBD_REP_ACK);
513 send_request(sock, NBD_OPT_ABORT, 0, NULL);
514 }
515
parse_sizes(char * buf,uint64_t * size,uint16_t * flags)516 void parse_sizes(char *buf, uint64_t *size, uint16_t *flags) {
517 memcpy(size, buf, sizeof(*size));
518 *size = ntohll(*size);
519 buf += sizeof(*size);
520 memcpy(flags, buf, sizeof(*flags));
521 *flags = ntohs(*flags);
522
523 if ((*size>>12) > (uint64_t)~0UL) {
524 printf("size = %luMB", (unsigned long)(*size>>20));
525 err("Exported device is too big for me. Get 64-bit machine :-(\n");
526 } else {
527 printf("size = %luMB", (unsigned long)(*size>>20));
528 }
529 printf("\n");
530 }
531
send_opt_exportname(int sock,u64 * rsize64,uint16_t * flags,bool can_opt_go,char * name,uint16_t global_flags)532 void send_opt_exportname(int sock, u64 *rsize64, uint16_t *flags, bool can_opt_go, char* name, uint16_t global_flags) {
533 send_request(sock, NBD_OPT_EXPORT_NAME, -1, name);
534 char b[sizeof(*flags) + sizeof(*rsize64)];
535 if(readit(sock, b, sizeof(b)) < 0 && can_opt_go) {
536 err("E: server does not support NBD_OPT_GO and dropped connection after sending NBD_OPT_EXPORT_NAME. Try -g.");
537 }
538 parse_sizes(b, rsize64, flags);
539 if(!(global_flags & NBD_FLAG_NO_ZEROES)) {
540 char buf[125];
541 readit(sock, buf, 124);
542 }
543 }
544
negotiate(int * sockp,u64 * rsize64,uint16_t * flags,char * name,uint32_t needed_flags,uint32_t client_flags,uint32_t do_opts,char * certfile,char * keyfile,char * cacertfile,char * tlshostname,bool tls,bool can_opt_go)545 void negotiate(int *sockp, u64 *rsize64, uint16_t *flags, char* name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts, char *certfile, char *keyfile, char *cacertfile, char *tlshostname, bool tls, bool can_opt_go) {
546 u64 magic;
547 uint16_t tmp;
548 uint16_t global_flags;
549 char buf[256] = "\0\0\0\0\0\0\0\0\0";
550 int sock = *sockp;
551
552 printf("Negotiation: ");
553 readit(sock, buf, 8);
554 if (strcmp(buf, INIT_PASSWD))
555 err("INIT_PASSWD bad");
556 printf(".");
557 readit(sock, &magic, sizeof(magic));
558 magic = ntohll(magic);
559 if (magic != opts_magic) {
560 if(magic == cliserv_magic) {
561 err("It looks like you're trying to connect to an oldstyle server. This is no longer supported since nbd 3.10.");
562 }
563 }
564 printf(".");
565 readit(sock, &tmp, sizeof(uint16_t));
566 global_flags = ntohs(tmp);
567 if((needed_flags & global_flags) != needed_flags) {
568 /* There's currently really only one reason why this
569 * check could possibly fail, but we may need to change
570 * this error message in the future... */
571 fprintf(stderr, "\nE: Server does not support listing exports\n");
572 exit(EXIT_FAILURE);
573 }
574
575 if (global_flags & NBD_FLAG_NO_ZEROES) {
576 client_flags |= NBD_FLAG_C_NO_ZEROES;
577 }
578 client_flags = htonl(client_flags);
579 if (write(sock, &client_flags, sizeof(client_flags)) < 0)
580 err("Failed/2.1: %m");
581
582 #if HAVE_GNUTLS && !defined(NOTLS)
583 /* TLS */
584 if (tls) {
585 int plainfd[2]; // [0] is used by the proxy, [1] is used by NBD
586 tlssession_t *s = NULL;
587 int ret;
588 uint32_t tmp32;
589 uint64_t tmp64;
590
591 send_request(sock, NBD_OPT_STARTTLS, 0, NULL);
592
593 if (read(sock, &tmp64, sizeof(tmp64)) < 0)
594 err("Could not read cliserv_magic: %m");
595 tmp64 = ntohll(tmp64);
596 if (tmp64 != NBD_OPT_REPLY_MAGIC) {
597 err("reply magic does not match");
598 }
599 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
600 err("Could not read option type: %m");
601 tmp32 = ntohl(tmp32);
602 if (tmp32 != NBD_OPT_STARTTLS)
603 err("Reply to wrong option");
604 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
605 err("Could not read option reply type: %m");
606 tmp32 = ntohl(tmp32);
607 if (tmp32 != NBD_REP_ACK) {
608 err("Option reply type != NBD_REP_ACK");
609 }
610 if (read(sock, &tmp32, sizeof(tmp32)) < 0) err(
611 "Could not read option data length: %m");
612 tmp32 = ntohl(tmp32);
613 if (tmp32 != 0) {
614 err("Option reply data length != 0");
615 }
616 s = tlssession_new(0,
617 keyfile,
618 certfile,
619 cacertfile,
620 tlshostname,
621 !cacertfile || !tlshostname, // insecure flag
622 #ifdef DODBG
623 1, // debug
624 #else
625 0, // debug
626 #endif
627 NULL, // quitfn
628 NULL, // erroutfn
629 NULL // opaque
630 );
631 if (!s)
632 err("Cannot establish TLS session");
633
634 if (socketpair(AF_UNIX, SOCK_STREAM, 0, plainfd) < 0)
635 err("Cannot get socket pair");
636
637 if (set_nonblocking(plainfd[0], 0) <0 ||
638 set_nonblocking(plainfd[1], 0) <0 ||
639 set_nonblocking(sock, 0) <0) {
640 close(plainfd[0]);
641 close(plainfd[1]);
642 err("Cannot set socket options");
643 }
644
645 ret = fork();
646 if (ret < 0)
647 err("Could not fork");
648 else if (ret == 0) {
649 // we are the child
650 if (daemon(0, 0) < 0) {
651 /* no one will see this */
652 fprintf(stderr, "Can't detach from the terminal");
653 exit(1);
654 }
655 signal (SIGPIPE, SIG_IGN);
656 close(plainfd[1]);
657 tlssession_mainloop(sock, plainfd[0], s);
658 close(sock);
659 close(plainfd[0]);
660 exit(0);
661 }
662 close(plainfd[0]);
663 close(sock);
664 sock = plainfd[1]; /* use the decrypted FD from now on */
665 *sockp = sock;
666 }
667 #else
668 if (keyfile) {
669 err("TLS requested but support not compiled in");
670 }
671 #endif
672
673 if(do_opts & NBDC_DO_LIST) {
674 ask_list(sock);
675 exit(EXIT_SUCCESS);
676 }
677
678 struct reply *rep = NULL;
679
680 if(!can_opt_go) {
681 send_opt_exportname(sock, rsize64, flags, can_opt_go, name, global_flags);
682 return;
683 }
684
685 send_info_request(sock, NBD_OPT_GO, 0, NULL, name);
686
687 do {
688 if(rep != NULL) free(rep);
689 rep = read_reply(sock);
690 if(rep && (rep->reply_type & NBD_REP_FLAG_ERROR)) {
691 switch(rep->reply_type) {
692 case NBD_REP_ERR_UNSUP:
693 /* server doesn't support NBD_OPT_GO or NBD_OPT_INFO,
694 * fall back to NBD_OPT_EXPORT_NAME */
695 send_opt_exportname(sock, rsize64, flags, can_opt_go, name, global_flags);
696 free(rep);
697 return;
698 case NBD_REP_ERR_POLICY:
699 if(rep->datasize > 0) {
700 char errstr[1024];
701 snprintf(errstr, sizeof errstr, "Connection not allowed by server policy. Server said: %s", rep->data);
702 err(errstr);
703 } else {
704 err("Connection not allowed by server policy.");
705 }
706 free(rep);
707 exit(EXIT_FAILURE);
708 default:
709 if(rep->datasize > 0) {
710 char errstr[1024];
711 snprintf(errstr, sizeof errstr, "Unknown error returned by server. Server said: %s", rep->data);
712 err(errstr);
713 } else {
714 err("Unknown error returned by server.");
715 }
716 free(rep);
717 exit(EXIT_FAILURE);
718 }
719 }
720 uint16_t info_type;
721 switch(rep->reply_type) {
722 case NBD_REP_INFO:
723 memcpy(&info_type, rep->data, 2);
724 info_type = htons(info_type);
725 switch(info_type) {
726 case NBD_INFO_EXPORT:
727 parse_sizes(rep->data + 2, rsize64, flags);
728 break;
729 default:
730 // ignore these, don't need them
731 break;
732 }
733 break;
734 case NBD_REP_ACK:
735 break;
736 default:
737 err_nonfatal("Unknown reply to NBD_OPT_GO received, ignoring");
738 }
739 } while(rep->reply_type != NBD_REP_ACK);
740 free(rep);
741 }
742
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 * num_conns,char ** certfile,char ** keyfile,char ** cacertfile,char ** tlshostname,bool * can_opt_go)743 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* num_conns, char **certfile, char **keyfile, char **cacertfile, char **tlshostname, bool *can_opt_go) {
744 bool retval = false;
745 cur_client = calloc(sizeof(CLIENT), 1);
746 cur_client->bs = 512;
747 cur_client->nconn = 1;
748 yyin = fopen(SYSCONFDIR "/nbdtab", "r");
749 yyout = fopen("/dev/null", "w");
750
751 if(!strncmp(cfgname, "/dev/", 5)) {
752 cfgname += 5;
753 }
754 cur_client->dev = cfgname;
755 if(yyin == NULL) {
756 fprintf(stderr, "while opening %s: ", SYSCONFDIR "/nbdtab");
757 perror("could not open config file");
758 goto out;
759 }
760 yyparse();
761
762 if(!found_config || parse_error) {
763 goto out;
764 }
765 *name_ptr = cur_client->name;
766 *dev_ptr = calloc(strlen(cur_client->dev) + 6, 1);
767 snprintf(*dev_ptr, strlen(cur_client->dev) + 6, "/dev/%s", cur_client->dev);
768 *hostn_ptr = cur_client->hostn;
769 *bs = cur_client->bs;
770 *timeout = cur_client->timeout;
771 *persist = cur_client->persist ? 1 : 0;
772 *swap = cur_client->swap ? 1 : 0;
773 *sdp = cur_client->sdp ? 1 : 0;
774 *b_unix = cur_client->b_unix ? 1 : 0;
775 *num_conns = cur_client->nconn;
776 *certfile = cur_client->cert;
777 *keyfile = cur_client->key;
778 *cacertfile = cur_client->cacert;
779 *tlshostname = cur_client->tlshostn;
780 *can_opt_go = !(cur_client->no_optgo);
781
782 retval = true;
783 out:
784 if(yyin != NULL) {
785 fclose(yyin);
786 }
787 if(yyout != NULL) {
788 fclose(yyout);
789 }
790 return retval;
791 }
792
setsizes(int nbd,u64 size64,int blocksize,u32 flags)793 void setsizes(int nbd, u64 size64, int blocksize, u32 flags) {
794 unsigned long size;
795 int read_only = (flags & NBD_FLAG_READ_ONLY) ? 1 : 0;
796
797 if (size64>>12 > (uint64_t)~0UL)
798 err("Device too large.\n");
799 else {
800 int tmp_blocksize = 4096;
801 if (size64 / (u64)blocksize <= (uint64_t)~0UL)
802 tmp_blocksize = blocksize;
803 if (ioctl(nbd, NBD_SET_BLKSIZE, tmp_blocksize) < 0) {
804 fprintf(stderr, "Failed to set blocksize %d\n",
805 tmp_blocksize);
806 err("Ioctl/1.1a failed: %m\n");
807 }
808 size = (unsigned long)(size64 / (u64)tmp_blocksize);
809 if (ioctl(nbd, NBD_SET_SIZE_BLOCKS, size) < 0)
810 err("Ioctl/1.1b failed: %m\n");
811 if (tmp_blocksize != blocksize) {
812 if (ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long)blocksize) < 0) {
813 fprintf(stderr, "Failed to set blocksize %d\n",
814 blocksize);
815 err("Ioctl/1.1c failed: %m\n");
816 }
817 }
818 fprintf(stderr, "bs=%d, sz=%" PRIu64 " bytes\n", blocksize, (u64)tmp_blocksize * size);
819 }
820
821 ioctl(nbd, NBD_CLEAR_SOCK);
822
823 /* ignore error as kernel may not support */
824 ioctl(nbd, NBD_SET_FLAGS, (unsigned long) flags);
825
826 if (ioctl(nbd, BLKROSET, (unsigned long) &read_only) < 0)
827 err("Unable to set read-only attribute for device");
828 }
829
set_timeout(int nbd,int timeout)830 void set_timeout(int nbd, int timeout) {
831 if (timeout) {
832 if (ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long)timeout) < 0)
833 err("Ioctl NBD_SET_TIMEOUT failed: %m\n");
834 fprintf(stderr, "timeout=%d\n", timeout);
835 }
836 }
837
finish_sock(int sock,int nbd,int swap)838 void finish_sock(int sock, int nbd, int swap) {
839 if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) {
840 if (errno == EBUSY)
841 err("Kernel doesn't support multiple connections\n");
842 else
843 err("Ioctl NBD_SET_SOCK failed: %m\n");
844 }
845
846 #ifndef __ANDROID__
847 if (swap)
848 mlockall(MCL_CURRENT | MCL_FUTURE);
849 #endif
850 }
851
852 static int
oom_adjust(const char * file,const char * value)853 oom_adjust(const char *file, const char *value)
854 {
855 int fd, rc;
856 size_t len;
857
858 fd = open(file, O_WRONLY);
859 if (fd < 0)
860 return -1;
861 len = strlen(value);
862 rc = write(fd, value, len) != (ssize_t) len;
863 close(fd);
864 return rc ? -1 : 0;
865 }
866
usage(char * errmsg,...)867 void usage(char* errmsg, ...) {
868 if(errmsg) {
869 char tmp[256];
870 va_list ap;
871 va_start(ap, errmsg);
872 snprintf(tmp, 256, "ERROR: %s\n\n", errmsg);
873 vfprintf(stderr, tmp, ap);
874 va_end(ap);
875 } else {
876 fprintf(stderr, "%s version %s\n", PROG_NAME, PACKAGE_VERSION);
877 }
878 #if HAVE_NETLINK
879 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] [-nonetlink|-L]\n\t[-readonly|-R] [-size|-B bytes] [-preinit|-P]\n");
880 #else
881 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\t[-readonly|-R] [-size|-B bytes] [-preinit|-P]\n");
882 #endif
883 fprintf(stderr, "Or : nbd-client -u (with same arguments as above)\n");
884 fprintf(stderr, "Or : nbd-client nbdX\n");
885 fprintf(stderr, "Or : nbd-client -d nbd_device\n");
886 fprintf(stderr, "Or : nbd-client -c nbd_device\n");
887 fprintf(stderr, "Or : nbd-client -h|--help\n");
888 fprintf(stderr, "Or : nbd-client -l|--list host\n");
889 fprintf(stderr, "Or : nbd-client -V|--version\n");
890 #if HAVE_GNUTLS && !defined(NOTLS)
891 fprintf(stderr, "All commands that connect to a host also take:\n\t[-F|-certfile certfile] [-K|-keyfile keyfile]\n\t[-A|-cacertfile cacertfile] [-H|-tlshostname hostname] [-x|-enable-tls]\n");
892 #endif
893 fprintf(stderr, "Default value for blocksize is 512\n");
894 fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */
895 fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n");
896 fprintf(stderr, "blocksizes other than 1024 without patches\n");
897 fprintf(stderr, "Default value for port is 10809. Note that port must always be numeric\n");
898 fprintf(stderr, "Bug reports and general discussion should go to %s\n", PACKAGE_BUGREPORT);
899 }
900
disconnect(char * device)901 void disconnect(char* device) {
902 int nbd = open(device, O_RDWR);
903
904 if (nbd < 0)
905 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
906 printf("disconnect, ");
907 if (ioctl(nbd, NBD_DISCONNECT)<0)
908 err("Ioctl failed: %m\n");
909 printf("sock, ");
910 if (ioctl(nbd, NBD_CLEAR_SOCK)<0)
911 err("Ioctl failed: %m\n");
912 printf("done\n");
913 close(nbd);
914 }
915
916 #if HAVE_NETLINK
917 static const char *short_opts = "-A:B:b:c:C:d:gH:hK:LlnN:PpRSst:uVx";
918 #else
919 static const char *short_opts = "-A:B:b:c:C:d:gH:hK:lnN:PpRSst:uVx";
920 #endif
921
main(int argc,char * argv[])922 int main(int argc, char *argv[]) {
923 char* port=NBD_DEFAULT_PORT;
924 int sock, nbd;
925 int blocksize=512;
926 char *hostname=NULL;
927 char *nbddev=NULL;
928 int swap=0;
929 int cont=0;
930 int timeout=0;
931 int sdp=0;
932 int G_GNUC_UNUSED nofork=0; // if -dNOFORK
933 pid_t main_pid;
934 u64 size64 = 0;
935 u64 force_size64 = 0;
936 uint16_t flags = 0;
937 bool force_read_only = false;
938 bool preinit = false;
939 int c;
940 int nonspecial=0;
941 int b_unix=0;
942 char* name="";
943 uint16_t needed_flags=0;
944 uint32_t cflags=NBD_FLAG_C_FIXED_NEWSTYLE;
945 uint32_t opts=0;
946 sigset_t block, old;
947 char *certfile = NULL;
948 char *keyfile = NULL;
949 char *cacertfile = NULL;
950 char *tlshostname = NULL;
951 bool tls = false;
952 struct sigaction sa;
953 int num_connections = 1;
954 int netlink = HAVE_NETLINK;
955 int need_disconnect = 0;
956 int *sockfds;
957 struct option long_options[] = {
958 { "cacertfile", required_argument, NULL, 'A' },
959 { "block-size", required_argument, NULL, 'b' },
960 { "size", required_argument, NULL, 'B' },
961 { "check", required_argument, NULL, 'c' },
962 { "connections", required_argument, NULL, 'C'},
963 { "disconnect", required_argument, NULL, 'd' },
964 { "certfile", required_argument, NULL, 'F' },
965 { "no-optgo", no_argument, NULL, 'g' },
966 { "help", no_argument, NULL, 'h' },
967 { "tlshostname", required_argument, NULL, 'H' },
968 { "keyfile", required_argument, NULL, 'K' },
969 { "list", no_argument, NULL, 'l' },
970 #if HAVE_NETLINK
971 { "nonetlink", no_argument, NULL, 'L' },
972 #endif
973 { "systemd-mark", no_argument, NULL, 'm' },
974 { "nofork", no_argument, NULL, 'n' },
975 { "name", required_argument, NULL, 'N' },
976 { "persist", no_argument, NULL, 'p' },
977 { "preinit", no_argument, NULL, 'P' },
978 { "readonly", no_argument, NULL, 'R' },
979 { "sdp", no_argument, NULL, 'S' },
980 { "swap", no_argument, NULL, 's' },
981 { "timeout", required_argument, NULL, 't' },
982 { "unix", no_argument, NULL, 'u' },
983 { "version", no_argument, NULL, 'V' },
984 { "enable-tls", no_argument, NULL, 'x' },
985 { 0, 0, 0, 0 },
986 };
987 int i;
988 bool can_opt_go = true;
989
990 logging(MY_NAME);
991
992 #if HAVE_GNUTLS && !defined(NOTLS)
993 tlssession_init();
994 #endif
995
996 while((c=getopt_long_only(argc, argv, short_opts, long_options, NULL))>=0) {
997 switch(c) {
998 case 1:
999 // non-option argument
1000 if(strchr(optarg, '=')) {
1001 // old-style 'bs=' or 'timeout='
1002 // argument
1003 fprintf(stderr, "WARNING: old-style command-line argument encountered. This is deprecated.\n");
1004 if(!strncmp(optarg, "bs=", 3)) {
1005 optarg+=3;
1006 goto blocksize;
1007 }
1008 if(!strncmp(optarg, "timeout=", 8)) {
1009 optarg+=8;
1010 goto timeout;
1011 }
1012 usage("unknown option %s encountered", optarg);
1013 exit(EXIT_FAILURE);
1014 }
1015 switch(nonspecial++) {
1016 case 0:
1017 // host
1018 hostname=optarg;
1019 break;
1020 case 1:
1021 // port
1022 if(!strtol(optarg, NULL, 0)) {
1023 // not parseable as a number, assume it's the device
1024 nbddev = optarg;
1025 nonspecial++;
1026 } else {
1027 port = optarg;
1028 }
1029 break;
1030 case 2:
1031 // device
1032 nbddev = optarg;
1033 break;
1034 default:
1035 usage("too many non-option arguments specified");
1036 exit(EXIT_FAILURE);
1037 }
1038 break;
1039 case 'b':
1040 blocksize:
1041 blocksize=(int)strtol(optarg, NULL, 0);
1042 if(blocksize == 0 || (blocksize % 512) != 0) {
1043 fprintf(stderr, "E: blocksize is not a multiple of 512! This is not allowed\n");
1044 exit(EXIT_FAILURE);
1045 }
1046 break;
1047 case 'B':
1048 force_size64=(u64)strtoull(optarg, NULL, 0);
1049 if(force_size64 == 0) {
1050 fprintf(stderr, "E: Invalid size\n");
1051 exit(EXIT_FAILURE);
1052 }
1053 break;
1054 case 'c':
1055 return check_conn(optarg, 1);
1056 case 'C':
1057 num_connections = (int)strtol(optarg, NULL, 0);
1058 break;
1059 case 'd':
1060 need_disconnect = 1;
1061 nbddev = strdup(optarg);
1062 break;
1063 case 'g':
1064 can_opt_go = false;
1065 break;
1066 case 'h':
1067 usage(NULL);
1068 exit(EXIT_SUCCESS);
1069 case 'l':
1070 needed_flags |= NBD_FLAG_FIXED_NEWSTYLE;
1071 opts |= NBDC_DO_LIST;
1072 nbddev="";
1073 break;
1074 #if HAVE_NETLINK
1075 case 'L':
1076 netlink = 0;
1077 break;
1078 #endif
1079 case 'm':
1080 argv[0][0] = '@';
1081 break;
1082 case 'n':
1083 nofork=1;
1084 break;
1085 case 'N':
1086 name=optarg;
1087 break;
1088 case 'p':
1089 cont=1;
1090 break;
1091 case 'P':
1092 preinit = true;
1093 break;
1094 case 'R':
1095 force_read_only = true;
1096 break;
1097 case 's':
1098 swap=1;
1099 break;
1100 case 'S':
1101 sdp=1;
1102 break;
1103 case 't':
1104 timeout:
1105 timeout=strtol(optarg, NULL, 0);
1106 break;
1107 case 'u':
1108 b_unix = 1;
1109 break;
1110 case 'V':
1111 printf("This is %s, from %s\n", PROG_NAME, PACKAGE_STRING);
1112 return 0;
1113 #if HAVE_GNUTLS && !defined(NOTLS)
1114 case 'x':
1115 tls = true;
1116 break;
1117 case 'F':
1118 certfile=strdup(optarg);
1119 break;
1120 case 'K':
1121 keyfile=strdup(optarg);
1122 break;
1123 case 'A':
1124 cacertfile=strdup(optarg);
1125 break;
1126 case 'H':
1127 tlshostname=strdup(optarg);
1128 break;
1129 #else
1130 case 'F':
1131 case 'K':
1132 case 'H':
1133 case 'A':
1134 fprintf(stderr, "E: TLS support not compiled in\n");
1135 exit(EXIT_FAILURE);
1136 #endif
1137 default:
1138 fprintf(stderr, "E: option eaten by 42 mice\n");
1139 exit(EXIT_FAILURE);
1140 }
1141 }
1142
1143 if (need_disconnect) {
1144 if (netlink)
1145 netlink_disconnect(nbddev);
1146 else
1147 disconnect(nbddev);
1148 exit(EXIT_SUCCESS);
1149 }
1150 #ifdef __ANDROID__
1151 if (swap)
1152 err("swap option unsupported on Android because mlockall is unsupported.");
1153 #endif
1154 if(hostname) {
1155 if((!name || !nbddev) && !(opts & NBDC_DO_LIST)) {
1156 if(!strncmp(hostname, "nbd", 3) || !strncmp(hostname, "/dev/nbd", 8)) {
1157 if(!get_from_config(hostname, &name, &nbddev, &hostname, &blocksize, &timeout, &cont, &swap, &sdp, &b_unix, &port, &num_connections, &certfile, &keyfile, &cacertfile, &tlshostname, &can_opt_go)) {
1158 usage("no valid configuration for specified device found", hostname);
1159 exit(EXIT_FAILURE);
1160 }
1161 } else if (!netlink) {
1162 usage("not enough information specified, and argument didn't look like an nbd device");
1163 exit(EXIT_FAILURE);
1164 }
1165 }
1166 } else {
1167 usage("no information specified");
1168 exit(EXIT_FAILURE);
1169 }
1170
1171 if (keyfile && !certfile)
1172 certfile = strdup(keyfile);
1173
1174 if (certfile != NULL || keyfile != NULL || cacertfile != NULL || tlshostname != NULL) {
1175 tls = true;
1176 }
1177
1178 if (preinit) {
1179 if (tls) {
1180 fprintf(stderr, "E: preinit connection cannot be used with TLS\n");
1181 exit(EXIT_FAILURE);
1182 }
1183 if (!force_size64) {
1184 fprintf(stderr, "E: preinit connection requires specifying size\n");
1185 exit(EXIT_FAILURE);
1186 }
1187 }
1188
1189 if (!tlshostname && hostname && !b_unix)
1190 tlshostname = strdup(hostname);
1191
1192 if (netlink)
1193 nofork = 1;
1194
1195 if((force_size64 % blocksize) != 0) {
1196 fprintf(stderr, "E: size (" PRIu64 " bytes) is not a multiple of blocksize (%d)!\n", force_size64, blocksize);
1197 exit(EXIT_FAILURE);
1198 }
1199
1200 if(strlen(name)==0 && !(opts & NBDC_DO_LIST)) {
1201 printf("Warning: the oldstyle protocol is no longer supported.\nThis method now uses the newstyle protocol with a default export\n");
1202 }
1203
1204 if(!(opts & NBDC_DO_LIST) && !netlink) {
1205 nbd = open(nbddev, O_RDWR);
1206 if (nbd < 0)
1207 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
1208 }
1209
1210 if (netlink) {
1211 sockfds = malloc(sizeof(int) * num_connections);
1212 if (!sockfds)
1213 err("Cannot allocate the socket fd's array");
1214 }
1215
1216 for (i = 0; i < num_connections; i++) {
1217 if (b_unix)
1218 sock = openunix(hostname);
1219 else
1220 sock = opennet(hostname, port, sdp);
1221 if (sock < 0)
1222 exit(EXIT_FAILURE);
1223
1224 if (!preinit)
1225 negotiate(&sock, &size64, &flags, name, needed_flags, cflags, opts, certfile, keyfile, cacertfile, tlshostname, tls, can_opt_go);
1226 if (force_read_only)
1227 flags |= NBD_FLAG_READ_ONLY;
1228 if (force_size64)
1229 size64 = force_size64;
1230 if (netlink) {
1231 sockfds[i] = sock;
1232 continue;
1233 }
1234
1235 if (i == 0) {
1236 setsizes(nbd, size64, blocksize, flags);
1237 set_timeout(nbd, timeout);
1238 }
1239 finish_sock(sock, nbd, swap);
1240 if (swap) {
1241 if (keyfile)
1242 fprintf(stderr, "Warning: using swap and TLS is prone to deadlock\n");
1243 /* try linux >= 2.6.36 interface first */
1244 if (oom_adjust("/proc/self/oom_score_adj", "-1000")) {
1245 /* fall back to linux <= 2.6.35 interface */
1246 oom_adjust("/proc/self/oom_adj", "-17");
1247 }
1248 }
1249 }
1250
1251 if (netlink) {
1252 int index = -1;
1253 if (nbddev) {
1254 if (sscanf(nbddev, "/dev/nbd%d", &index) != 1)
1255 err("Invalid nbd device target\n");
1256 }
1257 netlink_configure(index, sockfds, num_connections,
1258 size64, blocksize, flags, timeout);
1259 return 0;
1260 }
1261 /* Go daemon */
1262
1263 #ifndef NOFORK
1264 if(!nofork) {
1265 if (daemon(0,0) < 0)
1266 err("Cannot detach from terminal");
1267 }
1268
1269 memset(&sa, 0, sizeof(sa));
1270 sa.sa_handler = SIG_IGN;
1271 sigaction(SIGCHLD, &sa, NULL);
1272 #endif
1273 /* For child to check its parent */
1274 main_pid = getpid();
1275 do {
1276 #ifndef NOFORK
1277
1278 sigfillset(&block);
1279 sigdelset(&block, SIGKILL);
1280 sigdelset(&block, SIGTERM);
1281 sigdelset(&block, SIGPIPE);
1282 sigprocmask(SIG_SETMASK, &block, &old);
1283
1284 if (!fork()) {
1285 /* Due to a race, the kernel NBD driver cannot
1286 * call for a reread of the partition table
1287 * in the handling of the NBD_DO_IT ioctl().
1288 * Therefore, this is done in the first open()
1289 * of the device. We therefore make sure that
1290 * the device is opened at least once after the
1291 * connection was made. This has to be done in a
1292 * separate process, since the NBD_DO_IT ioctl()
1293 * does not return until the NBD device has
1294 * disconnected.
1295 */
1296 struct timespec req = {
1297 .tv_sec = 0,
1298 .tv_nsec = 100000000,
1299 };
1300 while(check_conn(nbddev, 0)) {
1301 if (main_pid != getppid()) {
1302 /* check_conn() will not return 0 when nbd disconnected
1303 * and parent exited during this loop. So the child has to
1304 * explicitly check parent identity and exit if parent
1305 * exited */
1306 exit(0);
1307 }
1308 nanosleep(&req, NULL);
1309 }
1310 if(open(nbddev, O_RDONLY) < 0) {
1311 perror("could not open device for updating partition table");
1312 }
1313 exit(0);
1314 }
1315 #endif
1316
1317 if (ioctl(nbd, NBD_DO_IT) < 0) {
1318 int error = errno;
1319 fprintf(stderr, "nbd,%d: Kernel call returned: %s\n", main_pid, strerror(errno));
1320 if(error==EBADR) {
1321 /* The user probably did 'nbd-client -d' on us.
1322 * quit */
1323 cont=0;
1324 } else {
1325 if(cont) {
1326 u64 new_size;
1327 uint16_t new_flags;
1328
1329 close(sock); close(nbd);
1330 for (;;) {
1331 fprintf(stderr, " Reconnecting\n");
1332 if (b_unix)
1333 sock = openunix(hostname);
1334 else
1335 sock = opennet(hostname, port, sdp);
1336 if (sock >= 0)
1337 break;
1338 sleep (1);
1339 }
1340 nbd = open(nbddev, O_RDWR);
1341 if (nbd < 0)
1342 err("Cannot open NBD: %m");
1343 negotiate(&sock, &new_size, &new_flags, name, needed_flags, cflags, opts, certfile, keyfile, cacertfile, tlshostname, tls, can_opt_go);
1344 if (size64 != new_size) {
1345 err("Size of the device changed. Bye");
1346 }
1347 setsizes(nbd, size64, blocksize,
1348 new_flags);
1349
1350 set_timeout(nbd, timeout);
1351 finish_sock(sock,nbd,swap);
1352 }
1353 }
1354 } else {
1355 /* We're on 2.4. It's not clearly defined what exactly
1356 * happened at this point. Probably best to quit, now
1357 */
1358 fprintf(stderr, "Kernel call returned.\n");
1359 cont=0;
1360 }
1361 } while(cont);
1362 printf("sock, ");
1363 ioctl(nbd, NBD_CLEAR_SOCK);
1364 printf("done\n");
1365 return 0;
1366 }
1367