Back to index

nbd  3.2
gznbd.c
Go to the documentation of this file.
00001 /* 
00002    (c) Marc Welz 2000, released under GPL, tested under Linux 2.2.17
00003 
00004    Most of the stuff cribbed from the nbd package written by Pavel Machek
00005 
00006    Unfortunately quite slow since zlib has to decompress all the stuff between
00007    seeks, so only suited to smaller files
00008    
00009    Could be a neat way to do userland encryption/steganography if you have 
00010    a crypto library which has a stdiolike interface to replace zlib
00011 
00012    Usage
00013 
00014      dd if=/dev/zero of=/tmp/image bs=1024 count=1024
00015      mke2fs -f /tmp/image
00016      mount -o loop /tmp/image /mnt/
00017      cp /bin/ls /mnt/
00018      umount /mnt
00019      sync
00020      gzip -9 /tmp/image
00021      gznbd /dev/nbd0 /tmp/image.gz
00022 
00023    gznbd does not background, from another terminal type
00024 
00025      mount -o ro,nocheck /dev/nbd0 /mnt/
00026      cd /mnt
00027      ls
00028      df
00029 
00030    ro is important, since writes will fail horribly and nochecks
00031    speeds the mount up nicely
00032 
00033  */
00034 
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <zlib.h>
00038 #include <errno.h>
00039 #include <string.h>
00040 #include <fcntl.h>
00041 #include <syslog.h>
00042 #include <unistd.h>
00043 
00044 #include <sys/ioctl.h>
00045 #include <sys/types.h>
00046 #include <sys/socket.h>
00047 
00048 #include <netinet/in.h>
00049 
00050 /* asm/types defines __u??, at least on my system */
00051 #include <asm/types.h>
00052 
00053 #define MY_NAME "gznbd"
00054 
00055 /* these headers take care of endianness */
00056 #include "../config.h"
00057 #include "../cliserv.h"
00058 
00059 #define BLOCK 1024
00060 
00061 /* don't ask me why this value, I only copied it */
00062 #define CHUNK BLOCK*20
00063 
00064 
00065 int main(int argc, char **argv)
00066 {
00067   int pr[2];
00068   int sk;
00069   int nbd;
00070   gzFile *gz;
00071   int gzerr;
00072 
00073   char chunk[CHUNK];
00074   struct nbd_request request;
00075   struct nbd_reply reply;
00076 
00077   u64 size;
00078   u64 from;
00079   u32 len;
00080 
00081   if(argc<3){
00082     printf("Usage: %s nbdevice gzfile [size]\n",argv[0]);
00083     exit(1);
00084   }
00085 
00086   gz=gzopen(argv[2], "rb");
00087   if(gz==NULL){
00088     fprintf(stderr,"%s: unable open compressed file %s\n",argv[0],argv[2]);
00089     exit(1);
00090   }
00091 
00092   if(argc>3){
00093     size=atol(argv[3]);
00094     if((size==0)||(size%BLOCK)){
00095       fprintf(stderr,"%s: %s does not appear to be a valid size\n",argv[0],argv[3]);
00096       exit(1);
00097     }
00098     printf("%s: file=%s, size=%Ld\n",argv[0],argv[2],size);
00099   } else {
00100     char buffer[BLOCK];
00101     int result;
00102 
00103     size=0;
00104     printf("%s: file=%s, seeking, ",argv[0],argv[2]);
00105     fflush(stdout);
00106 
00107     /* expensive seek to get file size */
00108     while(BLOCK==(result=gzread(gz,buffer,BLOCK))){
00109       size+=BLOCK;
00110     }
00111 
00112     if(result==0){
00113       printf("size=%Ld\n",size);
00114     } else {
00115       printf("failed\n");
00116       if(result<0){
00117         fprintf(stderr,"%s: read failed: %s\n",argv[0],gzerror(gz,&gzerr));
00118       } else {
00119         fprintf(stderr,"%s: incomplete last read, file has to be a multiple of %d\n",argv[0],BLOCK);
00120       }
00121       exit(1);
00122     }
00123 
00124     if(gzrewind(gz)!=0){
00125       fprintf(stderr,"%s: unable to rewind gzfile\n",argv[0]);
00126       exit(1);
00127     }
00128 
00129   }
00130 
00131   if(socketpair(AF_UNIX, SOCK_STREAM, 0, pr)){
00132     fprintf(stderr,"%s: unable to create socketpair: %s\n",argv[0],strerror(errno));
00133     exit(1);
00134   }
00135 
00136   switch(fork()){
00137     case -1 :
00138       fprintf(stderr,"%s: unable to fork: %s\n",argv[0],strerror(errno));
00139       exit(1);
00140       break;
00141     case 0 : /* child */
00142       gzclose(gz);
00143 
00144       close(pr[0]);
00145 
00146       sk=pr[1];
00147 
00148       nbd=open(argv[1], O_RDWR);
00149       if(nbd<0){
00150         fprintf(stderr,"%s: unable to open %s: %s\n",argv[0],argv[1],strerror(errno));
00151         exit(1);
00152       }
00153 
00154       if(ioctl(nbd,NBD_SET_SIZE,size)<0){
00155         fprintf(stderr,"%s: failed to set size for %s: %s\n",argv[0],argv[1],strerror(errno));
00156         exit(1);
00157       }
00158 
00159       ioctl(nbd, NBD_CLEAR_SOCK);
00160 
00161       if(ioctl(nbd,NBD_SET_SOCK,sk)<0){
00162         fprintf(stderr,"%s: failed to set socket for %s: %s\n",argv[0],argv[1],strerror(errno));
00163         exit(1);
00164       }
00165 
00166       if(ioctl(nbd,NBD_DO_IT)<0){
00167         fprintf(stderr,"%s: block device %s terminated: %s\n",argv[0],argv[1],strerror(errno));
00168       }
00169 
00170       ioctl(nbd, NBD_CLEAR_QUE);
00171       ioctl(nbd, NBD_CLEAR_SOCK);
00172 
00173       exit(0);
00174       
00175       break;
00176   }
00177 
00178   /* only parent here, child always exits */
00179 
00180   close(pr[1]);
00181   sk=pr[0];
00182 
00183   reply.magic=htonl(NBD_REPLY_MAGIC);
00184   reply.error=htonl(0);
00185 
00186   while(1){
00187 
00188     if(read(sk,&request,sizeof(request))!=sizeof(request)){
00189       fprintf(stderr,"%s: incomplete request\n",argv[0]);
00190     }
00191 
00192     memcpy(reply.handle,request.handle,sizeof(reply.handle));
00193 
00194     len=ntohl(request.len);
00195     from=ntohll(request.from);
00196 
00197 #ifdef TRACE
00198 fprintf(stderr,"%s: len=%d, from=%Ld\n",argv[0],len,from);
00199 #endif
00200 
00201     if(request.magic!=htonl(NBD_REQUEST_MAGIC)){
00202       fprintf(stderr,"%s: bad magic\n",argv[0]);
00203       reply.error=htonl(EIO); /* is that the right way of doing things ? */
00204     }
00205 
00206     if(ntohl(request.type)){
00207       fprintf(stderr,"%s: unsupported write request\n",argv[0]);
00208       reply.error=htonl(EROFS);
00209     }
00210 
00211     if(len+sizeof(struct nbd_reply)>CHUNK){
00212       fprintf(stderr,"%s: request too long\n",argv[0]);
00213       reply.error=htonl(EIO);
00214     }
00215 
00216     if(len+from>size){
00217       fprintf(stderr,"%s: request outside range\n",argv[0]);
00218       reply.error=htonl(EIO);
00219     }
00220 
00221     if(reply.error==htonl(0)){
00222       gzseek(gz,from,0);
00223       if(gzread(gz,chunk+sizeof(struct nbd_reply),len)!=len){
00224         fprintf(stderr,"%s: unable to read\n",argv[0]);
00225         reply.error=htonl(EIO);
00226         len=0;
00227       }
00228     } else {
00229       len=0;
00230     }
00231 
00232     memcpy(chunk,&reply,sizeof(struct nbd_reply));
00233     if(write(sk,chunk,len+sizeof(struct nbd_reply))!=(len+sizeof(struct nbd_reply))){
00234       fprintf(stderr,"%s: write failed: %s\n",argv[0],strerror(errno));
00235     }
00236   }
00237 
00238   gzclose(gz);
00239 
00240   return 0;
00241 }