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