|
Network Block Device @PACKAGE_VERSION@
|
00001 /* 00002 * Open connection for network block device 00003 * 00004 * Copyright 1997,1998 Pavel Machek, distribute under GPL 00005 * <pavel@atrey.karlin.mff.cuni.cz> 00006 * Copyright (c) 2002 - 2011 Wouter Verhelst <w@uter.be> 00007 * 00008 * Version 1.0 - 64bit issues should be fixed, now 00009 * Version 1.1 - added bs (blocksize) option (Alexey Guzeev, aga@permonline.ru) 00010 * Version 1.2 - I added new option '-d' to send the disconnect request 00011 * Version 2.0 - Version synchronised with server 00012 * Version 2.1 - Check for disconnection before INIT_PASSWD is received 00013 * to make errormsg a bit more helpful in case the server can't 00014 * open the exported file. 00015 * 16/03/2010 - Add IPv6 support. 00016 * Kitt Tientanopajai <kitt@kitty.in.th> 00017 * Neutron Soutmun <neo.neutron@gmail.com> 00018 * Suriya Soutmun <darksolar@gmail.com> 00019 */ 00020 00021 #include "config.h" 00022 #include "lfs.h" 00023 00024 #include <sys/ioctl.h> 00025 #include <sys/socket.h> 00026 #include <sys/un.h> 00027 #include <sys/types.h> 00028 #include <unistd.h> 00029 #include <netinet/tcp.h> 00030 #include <netinet/in.h> 00031 #include <netdb.h> 00032 #include "netdb-compat.h" 00033 #include <stdio.h> 00034 #include <fcntl.h> 00035 #include <syslog.h> 00036 #include <stdlib.h> 00037 #include <sys/mount.h> 00038 #include <sys/mman.h> 00039 #include <signal.h> 00040 #include <errno.h> 00041 #include <getopt.h> 00042 #include <stdarg.h> 00043 #include <stdbool.h> 00044 #include <time.h> 00045 00046 #include <linux/ioctl.h> 00047 #define MY_NAME "nbd_client" 00048 #include "cliserv.h" 00049 00050 #ifdef WITH_SDP 00051 #include <sdp_inet.h> 00052 #endif 00053 00054 #define NBDC_DO_LIST 1 00055 00056 int check_conn(char* devname, int do_print) { 00057 char buf[256]; 00058 char* p; 00059 int fd; 00060 int len; 00061 00062 if( (p=strrchr(devname, '/')) ) { 00063 devname=p+1; 00064 } 00065 if((p=strchr(devname, 'p'))) { 00066 /* We can't do checks on partitions. */ 00067 *p='\0'; 00068 } 00069 snprintf(buf, 256, "/sys/block/%s/pid", devname); 00070 if((fd=open(buf, O_RDONLY))<0) { 00071 if(errno==ENOENT) { 00072 return 1; 00073 } else { 00074 return 2; 00075 } 00076 } 00077 len=read(fd, buf, 256); 00078 if(len < 0) { 00079 perror("could not read from server"); 00080 close(fd); 00081 return 2; 00082 } 00083 buf[(len < 256) ? len : 255]='\0'; 00084 if(do_print) printf("%s\n", buf); 00085 close(fd); 00086 return 0; 00087 } 00088 00089 int opennet(char *name, char* portstr, int sdp) { 00090 int sock; 00091 struct addrinfo hints; 00092 struct addrinfo *ai = NULL; 00093 struct addrinfo *rp = NULL; 00094 int e; 00095 00096 memset(&hints,'\0',sizeof(hints)); 00097 hints.ai_family = AF_UNSPEC; 00098 hints.ai_socktype = SOCK_STREAM; 00099 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; 00100 hints.ai_protocol = IPPROTO_TCP; 00101 00102 e = getaddrinfo(name, portstr, &hints, &ai); 00103 00104 if(e != 0) { 00105 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e)); 00106 freeaddrinfo(ai); 00107 return -1; 00108 } 00109 00110 if(sdp) { 00111 #ifdef WITH_SDP 00112 if (ai->ai_family == AF_INET) 00113 ai->ai_family = AF_INET_SDP; 00114 else (ai->ai_family == AF_INET6) 00115 ai->ai_family = AF_INET6_SDP; 00116 #else 00117 err("Can't do SDP: I was not compiled with SDP support!"); 00118 #endif 00119 } 00120 00121 for(rp = ai; rp != NULL; rp = rp->ai_next) { 00122 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 00123 00124 if(sock == -1) 00125 continue; /* error */ 00126 00127 if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) 00128 break; /* success */ 00129 00130 close(sock); 00131 } 00132 00133 if (rp == NULL) { 00134 err_nonfatal("Socket failed: %m"); 00135 sock = -1; 00136 goto err; 00137 } 00138 00139 setmysockopt(sock); 00140 err: 00141 freeaddrinfo(ai); 00142 return sock; 00143 } 00144 00145 int openunix(const char *path) { 00146 int sock; 00147 struct sockaddr_un un_addr; 00148 memset(&un_addr, 0, sizeof(un_addr)); 00149 00150 un_addr.sun_family = AF_UNIX; 00151 if (strnlen(path, sizeof(un_addr.sun_path)) == sizeof(un_addr.sun_path)) { 00152 err_nonfatal("UNIX socket path too long"); 00153 return -1; 00154 } 00155 00156 strncpy(un_addr.sun_path, path, sizeof(un_addr.sun_path) - 1); 00157 00158 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 00159 err_nonfatal("SOCKET failed"); 00160 return -1; 00161 }; 00162 00163 if (connect(sock, &un_addr, sizeof(un_addr)) == -1) { 00164 err_nonfatal("CONNECT failed"); 00165 close(sock); 00166 return -1; 00167 } 00168 return sock; 00169 } 00170 00171 void ask_list(int sock) { 00172 uint32_t opt; 00173 uint32_t opt_server; 00174 uint32_t len; 00175 uint32_t reptype; 00176 uint64_t magic; 00177 int rlen; 00178 const int BUF_SIZE = 1024; 00179 char buf[BUF_SIZE]; 00180 00181 magic = ntohll(opts_magic); 00182 if (write(sock, &magic, sizeof(magic)) < 0) 00183 err("Failed/2.2: %m"); 00184 00185 /* Ask for the list */ 00186 opt = htonl(NBD_OPT_LIST); 00187 if(write(sock, &opt, sizeof(opt)) < 0) { 00188 err("writing list option failed: %m"); 00189 } 00190 /* Send the length (zero) */ 00191 len = htonl(0); 00192 if(write(sock, &len, sizeof(len)) < 0) { 00193 err("writing length failed: %m"); 00194 } 00195 /* newline, move away from the "Negotiation:" line */ 00196 printf("\n"); 00197 do { 00198 memset(buf, 0, 1024); 00199 if(read(sock, &magic, sizeof(magic)) < 0) { 00200 err("Reading magic from server: %m"); 00201 } 00202 if(read(sock, &opt_server, sizeof(opt_server)) < 0) { 00203 err("Reading option: %m"); 00204 } 00205 if(read(sock, &reptype, sizeof(reptype)) <0) { 00206 err("Reading reply from server: %m"); 00207 } 00208 if(read(sock, &len, sizeof(len)) < 0) { 00209 err("Reading length from server: %m"); 00210 } 00211 magic=ntohll(magic); 00212 len=ntohl(len); 00213 reptype=ntohl(reptype); 00214 if(magic != rep_magic) { 00215 err("Not enough magic from server"); 00216 } 00217 if(reptype & NBD_REP_FLAG_ERROR) { 00218 switch(reptype) { 00219 case NBD_REP_ERR_POLICY: 00220 fprintf(stderr, "\nE: listing not allowed by server.\n"); 00221 break; 00222 default: 00223 fprintf(stderr, "\nE: unexpected error from server.\n"); 00224 break; 00225 } 00226 if(len > 0 && len < BUF_SIZE) { 00227 if((rlen=read(sock, buf, len)) < 0) { 00228 fprintf(stderr, "\nE: could not read error message from server\n"); 00229 } else { 00230 buf[rlen] = '\0'; 00231 fprintf(stderr, "Server said: %s\n", buf); 00232 } 00233 } 00234 exit(EXIT_FAILURE); 00235 } else { 00236 if(len) { 00237 if(reptype != NBD_REP_SERVER) { 00238 err("Server sent us a reply we don't understand!"); 00239 } 00240 if(read(sock, &len, sizeof(len)) < 0) { 00241 fprintf(stderr, "\nE: could not read export name length from server\n"); 00242 exit(EXIT_FAILURE); 00243 } 00244 len=ntohl(len); 00245 if (len >= BUF_SIZE) { 00246 fprintf(stderr, "\nE: export name on server too long\n"); 00247 exit(EXIT_FAILURE); 00248 } 00249 if(read(sock, buf, len) < 0) { 00250 fprintf(stderr, "\nE: could not read export name from server\n"); 00251 exit(EXIT_FAILURE); 00252 } 00253 buf[len] = 0; 00254 printf("%s\n", buf); 00255 } 00256 } 00257 } while(reptype != NBD_REP_ACK); 00258 opt=htonl(NBD_OPT_ABORT); 00259 len=htonl(0); 00260 magic=htonll(opts_magic); 00261 if (write(sock, &magic, sizeof(magic)) < 0) 00262 err("Failed/2.2: %m"); 00263 if (write(sock, &opt, sizeof(opt)) < 0) 00264 err("Failed writing abort"); 00265 if (write(sock, &len, sizeof(len)) < 0) 00266 err("Failed writing length"); 00267 } 00268 00269 void negotiate(int sock, u64 *rsize64, uint16_t *flags, char* name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts) { 00270 u64 magic, size64; 00271 uint16_t tmp; 00272 uint16_t global_flags; 00273 char buf[256] = "\0\0\0\0\0\0\0\0\0"; 00274 uint32_t opt; 00275 uint32_t namesize; 00276 00277 printf("Negotiation: "); 00278 readit(sock, buf, 8); 00279 if (strcmp(buf, INIT_PASSWD)) 00280 err("INIT_PASSWD bad"); 00281 printf("."); 00282 readit(sock, &magic, sizeof(magic)); 00283 magic = ntohll(magic); 00284 if (magic != opts_magic) { 00285 if(magic == cliserv_magic) { 00286 err("It looks like you're trying to connect to an oldstyle server. This is no longer supported since nbd 3.10."); 00287 } 00288 } 00289 printf("."); 00290 readit(sock, &tmp, sizeof(uint16_t)); 00291 global_flags = ntohs(tmp); 00292 if((needed_flags & global_flags) != needed_flags) { 00293 /* There's currently really only one reason why this 00294 * check could possibly fail, but we may need to change 00295 * this error message in the future... */ 00296 fprintf(stderr, "\nE: Server does not support listing exports\n"); 00297 exit(EXIT_FAILURE); 00298 } 00299 00300 if (global_flags & NBD_FLAG_NO_ZEROES) { 00301 client_flags |= NBD_FLAG_C_NO_ZEROES; 00302 } 00303 client_flags = htonl(client_flags); 00304 if (write(sock, &client_flags, sizeof(client_flags)) < 0) 00305 err("Failed/2.1: %m"); 00306 00307 if(do_opts & NBDC_DO_LIST) { 00308 ask_list(sock); 00309 exit(EXIT_SUCCESS); 00310 } 00311 00312 /* Write the export name that we're after */ 00313 magic = htonll(opts_magic); 00314 if (write(sock, &magic, sizeof(magic)) < 0) 00315 err("Failed/2.2: %m"); 00316 00317 opt = ntohl(NBD_OPT_EXPORT_NAME); 00318 if (write(sock, &opt, sizeof(opt)) < 0) 00319 err("Failed/2.3: %m"); 00320 namesize = (u32)strlen(name); 00321 namesize = ntohl(namesize); 00322 if (write(sock, &namesize, sizeof(namesize)) < 0) 00323 err("Failed/2.4: %m"); 00324 if (write(sock, name, strlen(name)) < 0) 00325 err("Failed/2.4: %m"); 00326 00327 readit(sock, &size64, sizeof(size64)); 00328 size64 = ntohll(size64); 00329 00330 if ((size64>>12) > (uint64_t)~0UL) { 00331 printf("size = %luMB", (unsigned long)(size64>>20)); 00332 err("Exported device is too big for me. Get 64-bit machine :-(\n"); 00333 } else 00334 printf("size = %luMB", (unsigned long)(size64>>20)); 00335 00336 readit(sock, &tmp, sizeof(tmp)); 00337 *flags = (uint32_t)ntohs(tmp); 00338 00339 if (!(global_flags & NBD_FLAG_NO_ZEROES)) { 00340 readit(sock, &buf, 124); 00341 } 00342 printf("\n"); 00343 00344 *rsize64 = size64; 00345 } 00346 00347 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) { 00348 int fd = open(SYSCONFDIR "/nbdtab", O_RDONLY); 00349 bool retval = false; 00350 if(fd < 0) { 00351 fprintf(stderr, "while opening %s: ", SYSCONFDIR "/nbdtab"); 00352 perror("could not open config file"); 00353 goto out; 00354 } 00355 off_t size = lseek(fd, 0, SEEK_END); 00356 lseek(fd, 0, SEEK_SET); 00357 void *data = NULL; 00358 char *fsep = "\n\t# "; 00359 char *lsep = "\n#"; 00360 00361 if(size < 0) { 00362 perror("E: mmap'ing nbdtab"); 00363 exit(EXIT_FAILURE); 00364 } 00365 00366 data = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED, fd, 0); 00367 if(!strncmp(cfgname, "/dev/", 5)) { 00368 cfgname += 5; 00369 } 00370 char *loc = strstr((const char*)data, cfgname); 00371 if(!loc) { 00372 goto out; 00373 } 00374 size_t l = strlen(cfgname) + 6; 00375 *dev_ptr = malloc(l); 00376 snprintf(*dev_ptr, l, "/dev/%s", cfgname); 00377 00378 size_t line_len, field_len, ws_len; 00379 #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; } 00380 #define MOVE_NEXT line_len -= field_len + ws_len; loc += field_len + ws_len 00381 // find length of line 00382 line_len = strcspn(loc, lsep); 00383 // first field is the device node name, which we already know, so skip it 00384 CHECK_LEN; 00385 MOVE_NEXT; 00386 // next field is the hostname 00387 CHECK_LEN; 00388 *hostn_ptr = strndup(loc, field_len); 00389 MOVE_NEXT; 00390 // third field is the export name 00391 CHECK_LEN; 00392 *name_ptr = strndup(loc, field_len); 00393 if(ws_len + field_len > line_len) { 00394 // optional last field is not there, so return success 00395 retval = true; 00396 goto out; 00397 } 00398 MOVE_NEXT; 00399 CHECK_LEN; 00400 #undef CHECK_LEN 00401 #undef MOVE_NEXT 00402 // fourth field is the options field, a comma-separated field of options 00403 do { 00404 if(!strncmp(loc, "bs=", 3)) { 00405 *bs = (int)strtol(loc+3, &loc, 0); 00406 goto next; 00407 } 00408 if(!strncmp(loc, "timeout=", 8)) { 00409 *timeout = (int)strtol(loc+8, &loc, 0); 00410 goto next; 00411 } 00412 if(!strncmp(loc, "port=", 5)) { 00413 *port = strndup(loc+5, strcspn(loc+5, ",")); 00414 goto next; 00415 } 00416 if(!strncmp(loc, "persist", 7)) { 00417 loc += 7; 00418 *persist = 1; 00419 goto next; 00420 } 00421 if(!strncmp(loc, "swap", 4)) { 00422 *swap = 1; 00423 loc += 4; 00424 goto next; 00425 } 00426 if(!strncmp(loc, "sdp", 3)) { 00427 *sdp = 1; 00428 loc += 3; 00429 goto next; 00430 } 00431 if(!strncmp(loc, "unix", 4)) { 00432 *b_unix = 1; 00433 loc += 4; 00434 goto next; 00435 } 00436 // skip unknown options, with a warning unless they start with a '_' 00437 l = strcspn(loc, ","); 00438 if(*loc != '_') { 00439 char* s = strndup(loc, l); 00440 fprintf(stderr, "Warning: unknown option '%s' found in nbdtab file", s); 00441 free(s); 00442 } 00443 loc += l; 00444 next: 00445 if(*loc == ',') { 00446 loc++; 00447 } 00448 } while(strcspn(loc, lsep) > 0); 00449 retval = true; 00450 out: 00451 if(data != NULL) { 00452 munmap(data, size); 00453 } 00454 if(fd >= 0) { 00455 close(fd); 00456 } 00457 return retval; 00458 } 00459 00460 void setsizes(int nbd, u64 size64, int blocksize, u32 flags) { 00461 unsigned long size; 00462 int read_only = (flags & NBD_FLAG_READ_ONLY) ? 1 : 0; 00463 00464 if (size64>>12 > (uint64_t)~0UL) 00465 err("Device too large.\n"); 00466 else { 00467 int tmp_blocksize = 4096; 00468 if (size64 / (u64)blocksize <= (uint64_t)~0UL) 00469 tmp_blocksize = blocksize; 00470 if (ioctl(nbd, NBD_SET_BLKSIZE, tmp_blocksize) < 0) { 00471 fprintf(stderr, "Failed to set blocksize %d\n", 00472 tmp_blocksize); 00473 err("Ioctl/1.1a failed: %m\n"); 00474 } 00475 size = (unsigned long)(size64 / (u64)tmp_blocksize); 00476 if (ioctl(nbd, NBD_SET_SIZE_BLOCKS, size) < 0) 00477 err("Ioctl/1.1b failed: %m\n"); 00478 if (tmp_blocksize != blocksize) { 00479 if (ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long)blocksize) < 0) { 00480 fprintf(stderr, "Failed to set blocksize %d\n", 00481 blocksize); 00482 err("Ioctl/1.1c failed: %m\n"); 00483 } 00484 } 00485 fprintf(stderr, "bs=%d, sz=%llu bytes\n", blocksize, (u64)tmp_blocksize * size); 00486 } 00487 00488 ioctl(nbd, NBD_CLEAR_SOCK); 00489 00490 /* ignore error as kernel may not support */ 00491 ioctl(nbd, NBD_SET_FLAGS, (unsigned long) flags); 00492 00493 if (ioctl(nbd, BLKROSET, (unsigned long) &read_only) < 0) 00494 err("Unable to set read-only attribute for device"); 00495 } 00496 00497 void set_timeout(int nbd, int timeout) { 00498 if (timeout) { 00499 if (ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long)timeout) < 0) 00500 err("Ioctl NBD_SET_TIMEOUT failed: %m\n"); 00501 fprintf(stderr, "timeout=%d\n", timeout); 00502 } 00503 } 00504 00505 void finish_sock(int sock, int nbd, int swap) { 00506 if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) 00507 err("Ioctl NBD_SET_SOCK failed: %m\n"); 00508 00509 #ifndef __ANDROID__ 00510 if (swap) 00511 mlockall(MCL_CURRENT | MCL_FUTURE); 00512 #endif 00513 } 00514 00515 static int 00516 oom_adjust(const char *file, const char *value) 00517 { 00518 int fd, rc; 00519 size_t len; 00520 00521 fd = open(file, O_WRONLY); 00522 if (fd < 0) 00523 return -1; 00524 len = strlen(value); 00525 rc = write(fd, value, len) != (ssize_t) len; 00526 close(fd); 00527 return rc ? -1 : 0; 00528 } 00529 00530 void usage(char* errmsg, ...) { 00531 if(errmsg) { 00532 char tmp[256]; 00533 va_list ap; 00534 va_start(ap, errmsg); 00535 snprintf(tmp, 256, "ERROR: %s\n\n", errmsg); 00536 vfprintf(stderr, tmp, ap); 00537 va_end(ap); 00538 } else { 00539 fprintf(stderr, "nbd-client version %s\n", PACKAGE_VERSION); 00540 } 00541 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"); 00542 fprintf(stderr, "Or : nbd-client -u (with same arguments as above)\n"); 00543 fprintf(stderr, "Or : nbd-client nbdX\n"); 00544 fprintf(stderr, "Or : nbd-client -d nbd_device\n"); 00545 fprintf(stderr, "Or : nbd-client -c nbd_device\n"); 00546 fprintf(stderr, "Or : nbd-client -h|--help\n"); 00547 fprintf(stderr, "Or : nbd-client -l|--list host\n"); 00548 fprintf(stderr, "Default value for blocksize is 1024 (recommended for ethernet)\n"); 00549 fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */ 00550 fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n"); 00551 fprintf(stderr, "blocksizes other than 1024 without patches\n"); 00552 fprintf(stderr, "Default value for port is 10809. Note that port must always be numeric\n"); 00553 } 00554 00555 void disconnect(char* device) { 00556 int nbd = open(device, O_RDWR); 00557 00558 if (nbd < 0) 00559 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded."); 00560 printf("disconnect, "); 00561 if (ioctl(nbd, NBD_DISCONNECT)<0) 00562 err("Ioctl failed: %m\n"); 00563 printf("sock, "); 00564 if (ioctl(nbd, NBD_CLEAR_SOCK)<0) 00565 err("Ioctl failed: %m\n"); 00566 printf("done\n"); 00567 } 00568 00569 int main(int argc, char *argv[]) { 00570 char* port=NBD_DEFAULT_PORT; 00571 int sock, nbd; 00572 int blocksize=1024; 00573 char *hostname=NULL; 00574 char *nbddev=NULL; 00575 int swap=0; 00576 int cont=0; 00577 int timeout=0; 00578 int sdp=0; 00579 int G_GNUC_UNUSED nofork=0; // if -dNOFORK 00580 pid_t main_pid; 00581 u64 size64; 00582 uint16_t flags = 0; 00583 int c; 00584 int nonspecial=0; 00585 int b_unix=0; 00586 char* name=""; 00587 uint16_t needed_flags=0; 00588 uint32_t cflags=NBD_FLAG_C_FIXED_NEWSTYLE; 00589 uint32_t opts=0; 00590 sigset_t block, old; 00591 struct sigaction sa; 00592 struct option long_options[] = { 00593 { "block-size", required_argument, NULL, 'b' }, 00594 { "check", required_argument, NULL, 'c' }, 00595 { "disconnect", required_argument, NULL, 'd' }, 00596 { "help", no_argument, NULL, 'h' }, 00597 { "list", no_argument, NULL, 'l' }, 00598 { "name", required_argument, NULL, 'N' }, 00599 { "nofork", no_argument, NULL, 'n' }, 00600 { "persist", no_argument, NULL, 'p' }, 00601 { "sdp", no_argument, NULL, 'S' }, 00602 { "swap", no_argument, NULL, 's' }, 00603 { "systemd-mark", no_argument, NULL, 'm' }, 00604 { "timeout", required_argument, NULL, 't' }, 00605 { "unix", no_argument, NULL, 'u' }, 00606 { 0, 0, 0, 0 }, 00607 }; 00608 00609 logging(MY_NAME); 00610 00611 while((c=getopt_long_only(argc, argv, "-b:c:d:hlnN:pSst:u", long_options, NULL))>=0) { 00612 switch(c) { 00613 case 1: 00614 // non-option argument 00615 if(strchr(optarg, '=')) { 00616 // old-style 'bs=' or 'timeout=' 00617 // argument 00618 fprintf(stderr, "WARNING: old-style command-line argument encountered. This is deprecated.\n"); 00619 if(!strncmp(optarg, "bs=", 3)) { 00620 optarg+=3; 00621 goto blocksize; 00622 } 00623 if(!strncmp(optarg, "timeout=", 8)) { 00624 optarg+=8; 00625 goto timeout; 00626 } 00627 usage("unknown option %s encountered", optarg); 00628 exit(EXIT_FAILURE); 00629 } 00630 switch(nonspecial++) { 00631 case 0: 00632 // host 00633 hostname=optarg; 00634 break; 00635 case 1: 00636 // port 00637 if(!strtol(optarg, NULL, 0)) { 00638 // not parseable as a number, assume it's the device 00639 nbddev = optarg; 00640 nonspecial++; 00641 } else { 00642 port = optarg; 00643 } 00644 break; 00645 case 2: 00646 // device 00647 nbddev = optarg; 00648 break; 00649 default: 00650 usage("too many non-option arguments specified"); 00651 exit(EXIT_FAILURE); 00652 } 00653 break; 00654 case 'b': 00655 blocksize: 00656 blocksize=(int)strtol(optarg, NULL, 0); 00657 break; 00658 case 'c': 00659 return check_conn(optarg, 1); 00660 case 'd': 00661 disconnect(optarg); 00662 exit(EXIT_SUCCESS); 00663 case 'h': 00664 usage(NULL); 00665 exit(EXIT_SUCCESS); 00666 case 'l': 00667 needed_flags |= NBD_FLAG_FIXED_NEWSTYLE; 00668 opts |= NBDC_DO_LIST; 00669 nbddev=""; 00670 break; 00671 case 'm': 00672 argv[0][0] = '@'; 00673 break; 00674 case 'n': 00675 nofork=1; 00676 break; 00677 case 'N': 00678 name=optarg; 00679 break; 00680 case 'p': 00681 cont=1; 00682 break; 00683 case 's': 00684 swap=1; 00685 break; 00686 case 'S': 00687 sdp=1; 00688 break; 00689 case 't': 00690 timeout: 00691 timeout=strtol(optarg, NULL, 0); 00692 break; 00693 case 'u': 00694 b_unix = 1; 00695 break; 00696 default: 00697 fprintf(stderr, "E: option eaten by 42 mice\n"); 00698 exit(EXIT_FAILURE); 00699 } 00700 } 00701 00702 #ifdef __ANDROID__ 00703 if (swap) 00704 err("swap option unsupported on Android because mlockall is unsupported."); 00705 #endif 00706 if(hostname) { 00707 if((!name || !nbddev) && !(opts & NBDC_DO_LIST)) { 00708 if(!strncmp(hostname, "nbd", 3) || !strncmp(hostname, "/dev/nbd", 8)) { 00709 if(!get_from_config(hostname, &name, &nbddev, &hostname, &blocksize, &timeout, &cont, &swap, &sdp, &b_unix, &port)) { 00710 usage("no valid configuration for specified device found", hostname); 00711 exit(EXIT_FAILURE); 00712 } 00713 } else { 00714 usage("not enough information specified, and argument didn't look like an nbd device"); 00715 exit(EXIT_FAILURE); 00716 } 00717 } 00718 } else { 00719 usage("no information specified"); 00720 exit(EXIT_FAILURE); 00721 } 00722 00723 if(strlen(name)==0 && !(opts & NBDC_DO_LIST)) { 00724 printf("Warning: the oldstyle protocol is no longer supported.\nThis method now uses the newstyle protocol with a default export\n"); 00725 } 00726 00727 if (b_unix) 00728 sock = openunix(hostname); 00729 else 00730 sock = opennet(hostname, port, sdp); 00731 if (sock < 0) 00732 exit(EXIT_FAILURE); 00733 00734 negotiate(sock, &size64, &flags, name, needed_flags, cflags, opts); 00735 00736 nbd = open(nbddev, O_RDWR); 00737 if (nbd < 0) 00738 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded."); 00739 00740 setsizes(nbd, size64, blocksize, flags); 00741 set_timeout(nbd, timeout); 00742 finish_sock(sock, nbd, swap); 00743 if (swap) { 00744 /* try linux >= 2.6.36 interface first */ 00745 if (oom_adjust("/proc/self/oom_score_adj", "-1000")) { 00746 /* fall back to linux <= 2.6.35 interface */ 00747 oom_adjust("/proc/self/oom_adj", "-17"); 00748 } 00749 } 00750 00751 /* Go daemon */ 00752 00753 #ifndef NOFORK 00754 if(!nofork) { 00755 if (daemon(0,0) < 0) 00756 err("Cannot detach from terminal"); 00757 } 00758 00759 memset(&sa, 0, sizeof(sa)); 00760 sa.sa_handler = SIG_IGN; 00761 sigaction(SIGCHLD, &sa, NULL); 00762 #endif 00763 /* For child to check its parent */ 00764 main_pid = getpid(); 00765 do { 00766 #ifndef NOFORK 00767 00768 sigfillset(&block); 00769 sigdelset(&block, SIGKILL); 00770 sigdelset(&block, SIGTERM); 00771 sigdelset(&block, SIGPIPE); 00772 sigprocmask(SIG_SETMASK, &block, &old); 00773 00774 if (!fork()) { 00775 /* Due to a race, the kernel NBD driver cannot 00776 * call for a reread of the partition table 00777 * in the handling of the NBD_DO_IT ioctl(). 00778 * Therefore, this is done in the first open() 00779 * of the device. We therefore make sure that 00780 * the device is opened at least once after the 00781 * connection was made. This has to be done in a 00782 * separate process, since the NBD_DO_IT ioctl() 00783 * does not return until the NBD device has 00784 * disconnected. 00785 */ 00786 struct timespec req = { 00787 .tv_sec = 0, 00788 .tv_nsec = 100000000, 00789 }; 00790 while(check_conn(nbddev, 0)) { 00791 if (main_pid != getppid()) { 00792 /* check_conn() will not return 0 when nbd disconnected 00793 * and parent exited during this loop. So the child has to 00794 * explicitly check parent identity and exit if parent 00795 * exited */ 00796 exit(0); 00797 } 00798 nanosleep(&req, NULL); 00799 } 00800 open(nbddev, O_RDONLY); 00801 exit(0); 00802 } 00803 #endif 00804 00805 if (ioctl(nbd, NBD_DO_IT) < 0) { 00806 int error = errno; 00807 fprintf(stderr, "nbd,%d: Kernel call returned: %d", main_pid, error); 00808 if(error==EBADR) { 00809 /* The user probably did 'nbd-client -d' on us. 00810 * quit */ 00811 cont=0; 00812 } else { 00813 if(cont) { 00814 u64 new_size; 00815 uint16_t new_flags; 00816 00817 close(sock); close(nbd); 00818 for (;;) { 00819 fprintf(stderr, " Reconnecting\n"); 00820 if (b_unix) 00821 sock = openunix(hostname); 00822 else 00823 sock = opennet(hostname, port, sdp); 00824 if (sock >= 0) 00825 break; 00826 sleep (1); 00827 } 00828 nbd = open(nbddev, O_RDWR); 00829 if (nbd < 0) 00830 err("Cannot open NBD: %m"); 00831 negotiate(sock, &new_size, &new_flags, name, needed_flags, cflags, opts); 00832 if (size64 != new_size) { 00833 err("Size of the device changed. Bye"); 00834 } 00835 setsizes(nbd, size64, blocksize, 00836 new_flags); 00837 00838 set_timeout(nbd, timeout); 00839 finish_sock(sock,nbd,swap); 00840 } 00841 } 00842 } else { 00843 /* We're on 2.4. It's not clearly defined what exactly 00844 * happened at this point. Probably best to quit, now 00845 */ 00846 fprintf(stderr, "Kernel call returned."); 00847 cont=0; 00848 } 00849 } while(cont); 00850 printf("sock, "); 00851 ioctl(nbd, NBD_CLEAR_SOCK); 00852 printf("done\n"); 00853 return 0; 00854 }
1.7.3