00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "config.h"
00017 #include "lfs.h"
00018
00019 #include <sys/ioctl.h>
00020 #include <sys/socket.h>
00021 #include <sys/types.h>
00022 #include <unistd.h>
00023 #include <netinet/tcp.h>
00024 #include <netinet/in.h>
00025 #include <netdb.h>
00026 #include <stdio.h>
00027 #include <fcntl.h>
00028 #include <syslog.h>
00029 #include <stdlib.h>
00030 #include <sys/mount.h>
00031 #include <sys/mman.h>
00032 #include <errno.h>
00033
00034 #ifndef __GNUC__
00035 #error I need GCC to work
00036 #endif
00037
00038 #include <linux/ioctl.h>
00039 #define MY_NAME "nbd_client"
00040 #include "cliserv.h"
00041
00042 int check_conn(char* devname, int do_print) {
00043 char buf[256];
00044 char* p;
00045 int fd;
00046 int len;
00047 if(!strncmp(devname, "/dev/", 5)) {
00048 devname+=5;
00049 }
00050 if((p=strchr(devname, 'p'))) {
00051
00052 *p='\0';
00053 }
00054 snprintf(buf, 256, "/sys/block/%s/pid", devname);
00055 if((fd=open(buf, O_RDONLY))<0) {
00056 if(errno==ENOENT) {
00057 return 1;
00058 } else {
00059 return 2;
00060 }
00061 }
00062 len=read(fd, buf, 256);
00063 buf[len-1]='\0';
00064 if(do_print) printf("%s\n", buf);
00065 close (fd);
00066 return 0;
00067 }
00068
00069 int opennet(char *name, int port, int sdp) {
00070 int sock;
00071 struct sockaddr_in xaddrin;
00072 int xaddrinlen = sizeof(xaddrin);
00073 struct hostent *hostn;
00074 int af;
00075
00076 hostn = gethostbyname(name);
00077 if (!hostn)
00078 err("Gethostname failed: %h\n");
00079
00080 af = AF_INET;
00081 if(sdp) {
00082 #ifdef WITH_SDP
00083 af = AF_INET_SDP;
00084 #else
00085 err("Can't do SDP: I was not compiled with SDP support!");
00086 #endif
00087 }
00088 if ((sock = socket(af, SOCK_STREAM, IPPROTO_TCP)) < 0)
00089 err("Socket failed: %m");
00090
00091 xaddrin.sin_family = af;
00092 xaddrin.sin_port = htons(port);
00093 xaddrin.sin_addr.s_addr = *((int *) hostn->h_addr);
00094 if ((connect(sock, (struct sockaddr *) &xaddrin, xaddrinlen) < 0))
00095 err("Connect: %m");
00096
00097 setmysockopt(sock);
00098 return sock;
00099 }
00100
00101 void negotiate(int sock, u64 *rsize64, u32 *flags) {
00102 u64 magic, size64;
00103 char buf[256] = "\0\0\0\0\0\0\0\0\0";
00104
00105 printf("Negotiation: ");
00106 if (read(sock, buf, 8) < 0)
00107 err("Failed/1: %m");
00108 if (strlen(buf)==0)
00109 err("Server closed connection");
00110 if (strcmp(buf, INIT_PASSWD))
00111 err("INIT_PASSWD bad");
00112 printf(".");
00113 if (read(sock, &magic, sizeof(magic)) < 0)
00114 err("Failed/2: %m");
00115 magic = ntohll(magic);
00116 if (magic != cliserv_magic)
00117 err("Not enough cliserv_magic");
00118 printf(".");
00119
00120 if (read(sock, &size64, sizeof(size64)) < 0)
00121 err("Failed/3: %m\n");
00122 size64 = ntohll(size64);
00123
00124 #ifdef NBD_SET_SIZE_BLOCKS
00125 if ((size64>>10) > (~0UL >> 1)) {
00126 printf("size = %luMB", (unsigned long)(size64>>20));
00127 err("Exported device is too big for me. Get 64-bit machine :-(\n");
00128 } else
00129 printf("size = %luKB", (unsigned long)(size64>>10));
00130 #else
00131 if (size64 > (~0UL >> 1)) {
00132 printf("size = %luKB", (unsigned long)(size64>>10));
00133 err("Exported device is too big. Get 64-bit machine or newer kernel :-(\n");
00134 } else
00135 printf("size = %lu", (unsigned long)(size64));
00136 #endif
00137
00138 if (read(sock, flags, sizeof(*flags)) < 0)
00139 err("Failed/4: %m\n");
00140 *flags = ntohl(*flags);
00141
00142 if (read(sock, &buf, 124) < 0)
00143 err("Failed/5: %m\n");
00144 printf("\n");
00145
00146 *rsize64 = size64;
00147 }
00148
00149 void setsizes(int nbd, u64 size64, int blocksize, u32 flags) {
00150 unsigned long size;
00151 int read_only = (flags & NBD_FLAG_READ_ONLY) ? 1 : 0;
00152
00153 #ifdef NBD_SET_SIZE_BLOCKS
00154 if (size64/blocksize > (~0UL >> 1))
00155 err("Device too large.\n");
00156 else {
00157 int er;
00158 if (ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long)blocksize) < 0)
00159 err("Ioctl/1.1a failed: %m\n");
00160 size = (unsigned long)(size64/blocksize);
00161 if ((er = ioctl(nbd, NBD_SET_SIZE_BLOCKS, size)) < 0)
00162 err("Ioctl/1.1b failed: %m\n");
00163 fprintf(stderr, "bs=%d, sz=%lu\n", blocksize, size);
00164 }
00165 #else
00166 if (size64 > (~0UL >> 1)) {
00167 err("Device too large.\n");
00168 } else {
00169 size = (unsigned long)size64;
00170 if (ioctl(nbd, NBD_SET_SIZE, size) < 0)
00171 err("Ioctl NBD_SET_SIZE failed: %m\n");
00172 }
00173 #endif
00174
00175 ioctl(nbd, NBD_CLEAR_SOCK);
00176
00177 if (ioctl(nbd, BLKROSET, (unsigned long) &read_only) < 0)
00178 err("Unable to set read-only attribute for device");
00179 }
00180
00181 void set_timeout(int nbd, int timeout) {
00182 #ifdef NBD_SET_TIMEOUT
00183 if (timeout) {
00184 if (ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long)timeout) < 0)
00185 err("Ioctl NBD_SET_TIMEOUT failed: %m\n");
00186 fprintf(stderr, "timeout=%d\n", timeout);
00187 }
00188 #endif
00189 }
00190
00191 void finish_sock(int sock, int nbd, int swap) {
00192 if (ioctl(nbd, NBD_SET_SOCK, sock) < 0)
00193 err("Ioctl NBD_SET_SOCK failed: %m\n");
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 mlockall(MCL_CURRENT | MCL_FUTURE);
00208 }
00209
00210 int main(int argc, char *argv[]) {
00211 int port, sock, nbd;
00212 int blocksize=1024;
00213 char *hostname, *nbddev;
00214 int swap=0;
00215 int cont=0;
00216 int timeout=0;
00217 int sdp=0;
00218 int nofork=0;
00219 u64 size64;
00220 u32 flags;
00221
00222 logging();
00223
00224 if (argc < 3) {
00225 errmsg:
00226 fprintf(stderr, "nbd-client version %s\n", PACKAGE_VERSION);
00227 fprintf(stderr, "Usage: nbd-client [bs=blocksize] [timeout=sec] host port nbd_device [-swap] [-persist] [-nofork]\n");
00228 fprintf(stderr, "Or : nbd-client -d nbd_device\n");
00229 fprintf(stderr, "Or : nbd-client -c nbd_device\n");
00230 fprintf(stderr, "Default value for blocksize is 1024 (recommended for ethernet)\n");
00231 fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n");
00232 fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n");
00233 fprintf(stderr, "blocksizes other than 1024 without patches\n");
00234 return 1;
00235 }
00236
00237 ++argv; --argc;
00238
00239 if (strcmp(argv[0], "-d")==0) {
00240 nbd = open(argv[1], O_RDWR);
00241 if (nbd < 0)
00242 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
00243 printf("Disconnecting: que, ");
00244 if (ioctl(nbd, NBD_CLEAR_QUE)< 0)
00245 err("Ioctl failed: %m\n");
00246 printf("disconnect, ");
00247 #ifdef NBD_DISCONNECT
00248 if (ioctl(nbd, NBD_DISCONNECT)<0)
00249 err("Ioctl failed: %m\n");
00250 printf("sock, ");
00251 #else
00252 fprintf(stderr, "Can't disconnect: I was not compiled with disconnect support!\n" );
00253 exit(1);
00254 #endif
00255 if (ioctl(nbd, NBD_CLEAR_SOCK)<0)
00256 err("Ioctl failed: %m\n");
00257 printf("done\n");
00258 return 0;
00259 }
00260 if(strcmp(argv[0], "-c")==0) {
00261 return check_conn(argv[1], 1);
00262 }
00263
00264 if (strncmp(argv[0], "bs=", 3)==0) {
00265 blocksize=atoi(argv[0]+3);
00266 ++argv; --argc;
00267 }
00268
00269 if (strncmp(argv[0], "timeout=", 8)==0) {
00270 timeout=atoi(argv[0]+8);
00271 ++argv; --argc;
00272 }
00273
00274 if (argc==0) goto errmsg;
00275 hostname=argv[0];
00276 ++argv; --argc;
00277
00278 if (argc==0) goto errmsg;
00279 port = atoi(argv[0]);
00280 ++argv; --argc;
00281
00282 if (argc==0) goto errmsg;
00283 nbddev = argv[0];
00284 nbd = open(nbddev, O_RDWR);
00285 if (nbd < 0)
00286 err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
00287 ++argv; --argc;
00288
00289 if (argc>3) goto errmsg;
00290 if (argc) {
00291 if(strncmp(argv[0], "-swap", 5)==0) {
00292 swap=1;
00293 ++argv;--argc;
00294 }
00295 }
00296 if (argc) {
00297 if(strncmp(argv[0], "-persist", 8)==0) {
00298 cont=1;
00299 ++argv;--argc;
00300 }
00301 }
00302 if (argc) {
00303 if(strncmp(argv[0], "-sdp", 4)==0) {
00304 sdp=1;
00305 ++argv;--argc;
00306 }
00307 }
00308 if (argc) {
00309 if(strncmp(argv[0], "-nofork", 7)==0) {
00310 nofork=1;
00311 ++argv;--argc;
00312 }
00313 }
00314 if(argc) goto errmsg;
00315 sock = opennet(hostname, port, sdp);
00316 argv=NULL; argc=0;
00317
00318 negotiate(sock, &size64, &flags);
00319 setsizes(nbd, size64, blocksize, flags);
00320 set_timeout(nbd, timeout);
00321 finish_sock(sock, nbd, swap);
00322
00323
00324
00325 daemon(0,0);
00326 do {
00327 #ifndef NOFORK
00328 if (!nofork) {
00329 if (fork()) {
00330 while(check_conn(nbddev, 0)) {
00331 sleep(1);
00332 }
00333 open(nbddev, O_RDONLY);
00334 exit(0);
00335 }
00336 }
00337 #endif
00338
00339 if (ioctl(nbd, NBD_DO_IT) < 0) {
00340 fprintf(stderr, "Kernel call returned: %m");
00341 if(errno==EBADR) {
00342
00343
00344 cont=0;
00345 } else {
00346 if(cont) {
00347 u64 new_size;
00348 u32 new_flags;
00349
00350 fprintf(stderr, " Reconnecting\n");
00351 close(sock); close(nbd);
00352 sock = opennet(hostname, port, sdp);
00353 nbd = open(nbddev, O_RDWR);
00354 negotiate(sock, &new_size, &new_flags);
00355 if (size64 != new_size) {
00356 err("Size of the device changed. Bye");
00357 }
00358 setsizes(nbd, size64, blocksize,
00359 new_flags);
00360
00361 set_timeout(nbd, timeout);
00362 finish_sock(sock,nbd,swap);
00363 }
00364 }
00365 } else {
00366
00367
00368
00369 fprintf(stderr, "Kernel call returned.");
00370 cont=0;
00371 }
00372 } while(cont);
00373 printf("Closing: que, ");
00374 ioctl(nbd, NBD_CLEAR_QUE);
00375 printf("sock, ");
00376 ioctl(nbd, NBD_CLEAR_SOCK);
00377 printf("done\n");
00378 return 0;
00379 }