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