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